[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 }
AC代码

 

posted @ 2019-06-25 07:42 huyufeifei 阅读(...) 评论(...) 编辑 收藏