bzoj3622: 已经没有什么好害怕的了

题面

先设fij表示前i个中有j个一定满足条件,且这j个映射到的目标位置两两不同。剩下的i - j个没有选。

然后求到最后fni的时候,还有n - i个空位,对应n - i个没有选的元素。乘上(n - i)!就是至少为i的方案数。

这些方案中,恰i个的只会被计算一次,而每种多于i个的(不妨设有j个)都会被计算C(j, i)次。于是减去。

 


 

容斥。显然可以n2。感觉容斥有两种,一种就是直接暴力套公式,还有就是这样按顺来,用正确的倒推前面的。

不妨设fij表示前i个糖果中有j个糖果比药片大。这里说一下为什么最后需要那个组合数。

因为你是减去“a比b大的对数多于i”,然后考虑你一个对数为j的方案,从中选i对出来就是组合数。

这Cji种你都会计算,而且都会乘上阶乘,导出这唯一的一种方案,也就是你这种方案被多算了Cji次。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 const int N = 2010, MO = 1e9 + 9;
 5 
 6 int a[N], b[N], f[N][N], n, k, g[N], pw[N], C[N][N];
 7 
 8 int main() {
 9 
10     //freopen("in.in", "r", stdin);
11     //freopen("my.out", "w", stdout);
12 
13     scanf("%d%d", &n, &k);
14     if((n + k) & 1) {
15         printf("%d\n", 0);
16         return 0;
17     }
18     k = (n + k) / 2;
19     for(int i = 1; i <= n; i++) {
20         scanf("%d", &a[i]);
21     }
22     for(int i = 1; i <= n; i++) {
23         scanf("%d", &b[i]);
24     }
25 
26     std::sort(a + 1, a + n + 1);
27     std::sort(b + 1, b + n + 1);
28     f[0][0] = 1;
29     int p = 0;
30     for(int i = 1; i <= n; i++) {
31         f[i][0] = 1;
32     }
33     for(int i = 1; i <= n; i++) {
34         while(b[p + 1] < a[i] && p < n) p++;
35 //        printf("i = %d p = %d \n", i, p);
36         for(int j = 1; j <= n; j++) {
37             f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * std::max(0, p - j + 1) % MO) % MO;
38 //            printf("%d %d = %d + %d * %d \n", i, j, f[i - 1][j], f[i - 1][j - 1], std::max(0, p - j + 1));
39         }
40     }
41     pw[0] = 1;
42     for(int i = 0; i <= n; i++) {
43         C[i][0] = C[i][i] = 1;
44         for(int j = 1; j < i; j++) {
45             C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO;
46         }
47         if(i) pw[i] = 1ll * pw[i - 1] * i % MO;
48     }
49     /*for(int i = 1; i <= n; i++) {
50         for(int j = 1; j <= n; j++) {
51             printf("%d %d = %d \n", i, j, f[i][j]);
52         }
53         puts("");
54     }*/
55 
56     for(int i = n; i >= k; i--) {
57         g[i] = 1ll * f[n][i] * pw[n - i] % MO;
58         //printf("%d = %d \n", i, g[i]);
59         for(int j = i + 1; j <= n; j++) {
60             //(g[i] += MO - g[j]) %= MO;
61             g[i] -= 1ll * g[j] * C[j][i] % MO;
62             if(g[i] < 0) g[i] += MO;
63             //printf("g -= %d * %d  = %lld \n", g[j], C[j][i], g[i]);
64         }
65         //printf("%d = %d \n", i, g[i]);
66     }
67     printf("%d\n", (g[k] % MO + MO) % MO);
68     return 0;
69 }
70 /*
71 4 2
72 5 15 35 45
73 10 20 30 40
74 
75 4
76 */
AC代码

之前说的那两种写法都是可以的...原理不知道。这是第二种写法。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 const int N = 2010, MO = 1e9 + 9;
 5 
 6 int a[N], b[N], f[N][N], n, k, g[N], pw[N], C[N][N];
 7 
 8 int main() {
 9 
10     //freopen("in.in", "r", stdin);
11     //freopen("my.out", "w", stdout);
12 
13     scanf("%d%d", &n, &k);
14     if((n + k) & 1) {
15         printf("%d\n", 0);
16         return 0;
17     }
18     k = (n + k) / 2;
19     for(int i = 1; i <= n; i++) {
20         scanf("%d", &a[i]);
21     }
22     for(int i = 1; i <= n; i++) {
23         scanf("%d", &b[i]);
24     }
25 
26     std::sort(a + 1, a + n + 1);
27     std::sort(b + 1, b + n + 1);
28     f[0][0] = 1;
29     int p = 0;
30     for(int i = 1; i <= n; i++) {
31         f[i][0] = 1;
32     }
33     for(int i = 1; i <= n; i++) {
34         while(b[p + 1] < a[i] && p < n) p++;
35 //        printf("i = %d p = %d \n", i, p);
36         for(int j = 1; j <= n; j++) {
37             f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * std::max(0, p - j + 1) % MO) % MO;
38 //            printf("%d %d = %d + %d * %d \n", i, j, f[i - 1][j], f[i - 1][j - 1], std::max(0, p - j + 1));
39         }
40     }
41     pw[0] = 1;
42     for(int i = 0; i <= n; i++) {
43         C[i][0] = C[i][i] = 1;
44         for(int j = 1; j < i; j++) {
45             C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO;
46         }
47         if(i) pw[i] = 1ll * pw[i - 1] * i % MO;
48     }
49     /*for(int i = 1; i <= n; i++) {
50         for(int j = 1; j <= n; j++) {
51             printf("%d %d = %d \n", i, j, f[i][j]);
52         }
53         puts("");
54     }*/
55 
56     /*for(int i = n; i >= k; i--) {
57         g[i] = 1ll * f[n][i] * pw[n - i] % MO;
58         //printf("%d = %d \n", i, g[i]);
59         for(int j = i + 1; j <= n; j++) {
60             //(g[i] += MO - g[j]) %= MO;
61             g[i] -= 1ll * g[j] * C[j][i] % MO;
62             if(g[i] < 0) g[i] += MO;
63             //printf("g -= %d * %d  = %lld \n", g[j], C[j][i], g[i]);
64         }
65         //printf("%d = %d \n", i, g[i]);
66     }*/
67     int ans = 0;
68     for(int i = k; i <= n; i++) {
69         int temp = 1ll * f[n][i] * pw[n - i] % MO * C[i][k] % MO;
70         if((i - k) & 1) ans = (ans - temp) % MO;
71         else ans = (ans + temp) % MO;
72     }
73 
74 
75     printf("%d\n", (ans % MO + MO) % MO);
76     return 0;
77 }
78 /*
79 4 2
80 5 15 35 45
81 10 20 30 40
82 
83 4
84 */
AC代码

灵感来自bzoj2839

posted @ 2019-03-04 18:41  huyufeifei  阅读(155)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜