[HNOI2011]卡农
题意:求有多少种m个无序集合,其中每个集合由n个元素中的某些构成,每个元素出现偶数次,且无空集,且无两个集合相同。
解:因为每个集合不相同,所以可以求有序集合然后除以m!
设fm为m个集合时的答案。
考虑这个偶数的限制如何处理。前m - 1个随便放,最后一个根据奇偶性来决定。
不合法情况:最后一个是空集,最后一个和前面的重复。
分别减去fm-1和(i - 1) * fm-2 * (tot - (i - 2))。
后者的意义是先选出一个重复的位置,然后放m - 2个,然后考虑是哪个集合重合了。
随便放的数目就是totm↓,初值就是1和2两个都是0,因为1不满足出现偶数次,2的两个集合必定相同。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 5 const int N = 1000010, MO = 100000007; 6 7 int f[N], inv[N], invn[N], temp[N]; 8 9 inline int qpow(int a, int b) { 10 int ans(1); 11 while(b) { 12 if(b & 1) ans = (LL)ans * a % MO; 13 a = (LL)a * a % MO; 14 b = b >> 1; 15 } 16 return ans; 17 } 18 19 /*inline int C(int n, int m) { 20 if(n < 0 || m < 0 || n < m) { 21 return 0; 22 } 23 //printf("n = %d %d %d %d \n", n, fac[n], invn[m], invn[n - m]); 24 return (LL)fac[n] * invn[m] % MO * invn[n - m] % MO; 25 } */ 26 27 int main() { 28 int n, m; 29 scanf("%d%d", &n, &m); 30 int tot = qpow(2, n) - 1; 31 int lm = std::max(n ,m); 32 //printf("lm = %d \n", lm); 33 inv[0] = invn[0] = 1; 34 inv[1] = invn[1] = 1; 35 temp[0] = 1; 36 for(int i = 1; i <= lm; i++) { 37 temp[i] = (LL)temp[i - 1] * (tot + 1 - i) % MO; 38 } 39 for(int i = 2; i <= lm; i++) { 40 inv[i] = (LL)inv[MO % i] * (MO - MO / i) % MO; 41 invn[i] = (LL)invn[i - 1] * inv[i] % MO; 42 } 43 for(int i = 3; i <= m; i++) { 44 f[i] = temp[i - 1]; 45 //printf("f %d = %d tot = %d \n", i, f[i], tot); 46 (f[i] -= f[i - 1]) %= MO; 47 (f[i] -= (LL)f[i - 2] * (tot - i + 2) % MO * (i - 1) % MO) %= MO; 48 } 49 f[m] = (LL)f[m] * invn[m] % MO; 50 printf("%d\n", (f[m] + MO) % MO); 51 return 0; 52 }