• 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
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", g[j], C[j][i], g[i]);
    64         }
    65         //printf("%d = %d 
    ", i, g[i]);
    66     }
    67     printf("%d
    ", (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
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", 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 
    ", g[j], C[j][i], g[i]);
    64         }
    65         //printf("%d = %d 
    ", 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
    ", (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

  • 相关阅读:
    使用vimdiff作为svn diff的查看代码工具
    Source Insight :在 { 后敲回车后让代码自动缩进
    关于浏览器内核的一些小知识
    Linux内存点滴 用户进程内存空间
    自定义eclipse代码模板
    sqlplus 小记
    LD_PRELOAD的用法 以及链接库的用法
    如何更方便的使用sooset
    [hadoop源码阅读][0]初衷和各种资源
    hadoop streaming和pipes资料
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10472380.html
Copyright © 2020-2023  润新知