【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\n");
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\n",dp[k]);
59     }
60     return 0;
61 }
View Code

もう何も怖くない(呵呵

 

2017-04-06 14:16:58

转载于:https://www.cnblogs.com/Konjakmoyu/p/6673243.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值