• 【BZOJ 3622】3622: 已经没有什么好害怕的了(DP+容斥原理)


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

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 683  Solved: 328

    Description

    Input

    Output

    Sample Input

    4 2
    5 35 15 45
    40 20 10 30

    Sample Output

    4

    HINT


    输入的2*n个数字保证全不相同。


    还有输入应该是第二行是糖果,第三行是药片

    Source

    【分析】

      もう何も怖くない

      首先n+k为奇特判无解。

      然后知道要选多少组ai>bj的

      然后就选吧。

      先两个都排一遍序

      $f[i][j]$表示选了a的前$i$组后有$j$组$ai>bj$的,的方案数。

      这个很简单好吗!!(我昨天晚上看这题时候绝对脑抽)

      $f[i][j]=f[i-1][j]+f[i-1][j-1]*(mx[i]-j+1)$ 剩下的先不用管,后面乱排乘一个阶乘

      $mx[i]$表示最多前$mx[i]$个$b$数组小于$a[i]$

      但是!!不能保证刚好就等于你要的组数,可能大于它。于是容斥大法就来了。

      $dp[i]=f[n][i]*(n-i)!-dp[j]*C[j][i] (j>i)$

      组合数也递推就好了。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 2010
     8 #define Mod 1000000009
     9 #define LL long long
    10 
    11 LL mymax(LL x,LL y) {return x>y?x:y;}
    12 
    13 LL a[Maxn],b[Maxn],f[Maxn][Maxn],mx[Maxn],dp[Maxn],p[Maxn];
    14 LL c[Maxn][Maxn];
    15 
    16 int main()
    17 {
    18     LL n,k;
    19     scanf("%lld%lld",&n,&k);
    20     if((n+k)&1) printf("0
    ");
    21     else
    22     {
    23         k=(n+k)/2;
    24         for(LL i=1;i<=n;i++) scanf("%lld",&a[i]);
    25         for(LL i=1;i<=n;i++) scanf("%lld",&b[i]);
    26         sort(a+1,a+1+n);
    27         sort(b+1,b+1+n);
    28         LL st=0;
    29         for(LL i=1;i<=n;i++)
    30         {
    31             while(a[i]>b[st+1]&&st<n) st++;
    32             mx[i]=st;
    33         }
    34         memset(f,0,sizeof(f));
    35         for(int i=0;i<=n;i++) f[i][0]=1;
    36         for(LL i=1;i<=n;i++)
    37          for(LL j=1;j<=i;j++)
    38          {
    39              f[i][j]=(f[i-1][j]+f[i-1][j-1]*mymax(mx[i]-j+1,0))%Mod;
    40          }
    41         for(LL i=0;i<=n;i++) c[i][0]=1;
    42         for(LL i=1;i<=n;i++)
    43          for(LL j=1;j<=i;j++)
    44          {
    45              c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
    46          }
    47         p[0]=1;
    48         for(LL i=1;i<=n;i++) p[i]=(p[i-1]*i)%Mod;
    49         for(LL i=n;i>=k;i--)
    50         {
    51             dp[i]=(f[n][i]*p[n-i])%Mod;
    52             for(LL j=i+1;j<=n;j++)
    53             {
    54                 dp[i]=dp[i]-c[j][i]*dp[j];
    55                 dp[i]=(dp[i]%Mod+Mod)%Mod;
    56             }
    57         }
    58         printf("%lld
    ",dp[k]);
    59     }
    60     return 0;
    61 }
    View Code

    もう何も怖くない(呵呵

    2017-04-06 14:16:58

  • 相关阅读:
    项目8AspNetMvc_linq技术
    uniapp vue TV端,如何接收遥控器输入
    lisp单个文件的编译
    Oracle创建定时任务
    vue2安装less
    os.path.dirname用法
    shell学习(正则表达式)
    关于测试
    QTP学习笔记
    算法题:从有序数组中查找指定值
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6673243.html
Copyright © 2020-2023  润新知