bzoj 1879 [Sdoi2009]Bill的挑战
一般化的题目描述:
有$n$个属性,求恰好满足$k$个属性的物品个数
你有一个函数$q(S)$,可以快速算出至少满足属性集合$S$的物品个数(保证每个物品最多只会被统计一次)
设$f(S)$表示只满足属性集合$S$中的物品的个数,那么答案就是$\sum_{S \subseteq U \wedge |S| = k}f(S)$
设$f(S)=\sum\limits_{S \subseteq P}q(P)g(|P|)$,其中$|S|=k$,显然有$g(x)=(-1)^{x-k}$
证明:
对于一个物品$t$,假设它的属性集合为$Q$,且$S \subseteq Q$,且$|Q|=k+u$
那么它对$f(S)$的贡献是
$$\sum_{i=0}^{u}{u \choose i}(-1)^{i}=(-1+1)^{u}=[u=0]$$
也就是说$f(S)=\sum\limits_{S \subseteq P}q(P)(-1)^{|P|-k}$
也就是说
$$\begin{aligned}T&=\sum\limits_{S \subseteq U \wedge |S| = k}f(S) \\&=\sum\limits_{S \subseteq U \wedge |S| = k} \sum_{S \subseteq P}q(P)(-1)^{|P|-k} \\&=\sum\limits_{P \subseteq U \wedge |P| \ge k} q(P)(-1)^{|P|-k}{|P| \choose k}\end{aligned}$$
于是就做完了……
由于这道题的$q(S)$求法十分简单,在此就不赘述了
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int mod = 1e6 + 3; 5 char s[20][55]; 6 int n, k, vis[55], len; 7 ll pw(ll a, ll b) { 8 ll r = 1; 9 for( ; b ; b >>= 1, a = a * a % mod) if(b & 1) r = r * a % mod; 10 return r; 11 } 12 ll calc(int s) { 13 for(int i = 1 ; i <= len ; ++ i) { 14 vis[i] = 0; 15 } 16 for(int i = 1 ; i <= n ; ++ i) { 17 if((s >> (i - 1)) & 1) { 18 for(int j = 1 ; j <= len ; ++ j) { 19 char c = :: s[i][j]; 20 if(c == '?') continue; 21 if(vis[j] && vis[j] != c) { 22 return 0; 23 } 24 vis[j] = c; 25 } 26 } 27 } 28 29 ll res = 1; 30 for(int i = 1 ; i <= len ; ++ i) { 31 if(vis[i]) continue; 32 res = res * 26 % mod; 33 } 34 35 return res; 36 } 37 38 int C[20][20]; 39 40 void sol() { 41 scanf("%d%d", &n, &k); 42 for(int i = 1 ; i <= n ; ++ i) { 43 scanf("%s", s[i] + 1); 44 } 45 len = strlen(s[1] + 1); 46 int ans = 0; 47 for(int s = 0 ; s < (1 << n) ; ++ s) { 48 int cnt = 0; 49 for(int i = 1 ; i <= n ; ++ i) { 50 if((s >> (i - 1)) & 1) { 51 ++ cnt; 52 } 53 } 54 if(cnt >= k) { 55 ll sig = ((cnt - k) & 1) ? -1 : 1; 56 ans = (ans + sig * C[cnt][k] * calc(s)) % mod; 57 } 58 } 59 ans = (ans % mod + mod) % mod; 60 printf("%d\n", ans); 61 } 62 63 int main() { 64 C[0][0] = 1; 65 for(int i = 1 ; i < 20 ; ++ i) { 66 C[i][0] = 1; 67 for(int j = 1 ; j < 20 ; ++ j) { 68 C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod; 69 } 70 } 71 int T; scanf("%d", &T); 72 while(T --) sol(); 73 }