看数据范围是一种优良的传统,本题
N
≤
15
N\leq 15
N≤15,状压无疑了QAQ。
然后我们看到:刚好与 K K K 个串匹配的个数,就想到了容斥。
感觉自己思维好跳跃啊不过似乎也是正常思路?
由于是与 K K K 个串匹配,不能单纯的“奇加偶减”,我们用 f [ i ] f[i] f[i] 表示恰好与 K K K 个串匹配的串的个数, C n t [ i ] Cnt[i] Cnt[i] 表示与至少 K K K 个串匹配的串的个数。
画几个韦恩图(不过挺难画的),可以发现对于每个表示与至少
K
K
K 个串匹配的个数的“圆圈”都有交集,所以我们依次减去这些交集:
f [ i ] = C n t [ i ] − ∑ i + 1 N C [ j ] [ i ] ∗ f [ j ] f[i]=Cnt[i]-\sum\limits^N_{i+1} C[j][i] * f[j] f[i]=Cnt[i]−i+1∑NC[j][i]∗f[j]
对于
C
n
t
Cnt
Cnt 数组的计算,要根据每个字符串的集合算出它们的交集,然后根据这些集合表示的字符串的个数来判断应该把它加到哪个
C
n
t
Cnt
Cnt 中,这个过程很简单,详见代码(话说这个部分我开始以为自己的思路有问题,又是debug又是在草稿纸上画来画去,最后看了题解一怒之下删了
t
m
^{tm}
tm 一大段代码直接
A
A
A 了。(枯了)目前最差优解
r
k
2
rk2
rk2。
多测不清零==爆零n行泪
码风贼丑,见谅。
C o d e : Code: Code:
#include <cstdio>
#include <cstring>
#define MOD 1000003
#define MAXS 1 << 16
#define lowbit(x) (x & ~x + 1)
#define max(x, y) (x > y ? x : y)
char S[16][51], Union[MAXS][51];
int Pow[51] = {1}, Log[MAXS], bitlen[MAXS], C[16][16], f[16], Cnt[20];
bool vis[MAXS];
int main() {
for (int i(1); i <= 50; ++ i) Pow[i] = Pow[i - 1] * 26 % MOD;
for (int i(0); i < 16; ++ i) Log[1 << i] = i;
for (register int i(1); i < MAXS; ++ i) bitlen[i] = bitlen[i ^ lowbit(i)] + 1;
for (int i(0); i <= 15; ++ i) {
C[i][0] = 1;
for (int j(1); j <= i; ++ j) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
}
int T;
scanf("%d", &T);
while (T --) {
int N, K, len;
scanf("%d%d", &N, &K);
memset(vis, 0, sizeof(vis)), memset(Cnt, 0, sizeof(Cnt));
for (register int i(0); i < N; ++ i) scanf("%s", S[i]);
len = strlen(S[0]);
memset(Union, '\0', sizeof(Union));
for (register int i(0); i < 50; ++ i) Union[0][i] = '?';
for (register int i(1); i < 1 << N; ++ i) {
if (!vis[i ^ lowbit(i)]) strcpy(Union[i], Union[i ^ lowbit(i)]);
else {vis[i] = true; continue;}
register char * s(S[Log[lowbit(i)]]), * Uni(Union[i]);
for (register int j(0); j < len; ++ j)
if (Uni[j] != '?' && s[j] != '?' && Uni[j] != s[j]) {vis[i] = true; break;}
else if (s[j] != '?') Uni[j] = s[j];
}
for (register int i(1); i < 1 << N; ++ i) if (!vis[i] && bitlen[i] >= K) {
int cnt(0);
for (register int j(0); j < len; ++ j) if (Union[i][j] == '?') ++ cnt;
(Cnt[bitlen[i]] += Pow[cnt]) %= MOD;
}
for (int i(N); i >= K; -- i) {
f[i] = Cnt[i];
int sum(0);
for (int j(i + 1); j <= N; ++ j)
sum += C[j][i] * f[j], sum = (sum + MOD) % MOD;
f[i] = ((f[i] - sum) % MOD + MOD) % MOD;
}
printf("%d\n", f[K]);
}
}