bzoj 1879 容斥
暴力求容斥系数或者直接组合数求容斥系数都可以。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> #define PLI pair<LL, int> #define ull unsigned long long using namespace std; const int N = 55; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1000003; int n, k, m, Pow[N], num[1 << 15], C[N][N]; char s[20][55]; char t[55]; void init() { Pow[0] = 1; for(int i = 1; i < N; i++) Pow[i] = Pow[i-1] * 26 % mod; for(int i = 0; i < N; i++) { for(int j = 0; j <= i; j++) { if(!j || i == j) C[i][j] = 1; else C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod; } } } int cal(int state) { memset(t, '#', sizeof(t)); for(int j = 0; j < n; j++) { if((state>>j)&1) { for(int i = 0; i < m; i++) { if(s[j][i] != '?') { if(t[i] == '#') t[i] = s[j][i]; else if(t[i] != s[j][i]) return 0; } } } } int cnt = 0; for(int i = 0; i < m; i++) if(t[i] == '#') cnt++; return Pow[cnt]; } int solve(int k) { if(k == -1) return 0; int ans = 0; for(int s = 1; s < (1<<n); s++) { if(s) num[s] = num[s-(s&-s)] + 1; if(num[s] > k) { int val = cal(s); if((num[s] - k)&1) ans = (ans + 1ll*C[num[s]-1][k]*val) % mod; else ans = (ans - 1ll*C[num[s]-1][k]*val) % mod; } } return (Pow[m] - ans + mod) % mod; } int main() { init(); int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &k); for(int i = 0; i < n; i++) scanf("%s", s[i]); m = strlen(s[0]); printf("%d\n", (solve(k) - solve(k-1) + mod) % mod); } return 0; } /* */