10.06 容斥练习T2 DP+容斥原理(二项式反演)

Description

已经使 Modoka 有签订契约, 和自己一起战斗的想法后 , Mami 忽然感到自己不再是孤单一人了呢.
于是, 之前的谨慎的战斗作风也消失了 , 在对 Charlotte 的傀儡使用终曲——Tiro Finale后 , Mami 面临着即将被 Charlotte 的本体吃掉的局面.
这时, 已经多次面对过 Charlotte 的 Homura 告诉了学 OI 的你这样一个性质——Charlotte的结界中有两种具有能量的元素——一种是“糖果” , 另一种是“药片” , 每种各有 n 个. 在Charlotte 发动进攻前, “糖果”和“药片”会两两配对,若恰好“糖果”比“药片”能量大的组数比“药片”比“糖果”能量大的组数多 k 组, 则在这种局面下, Charlotte 的攻击会丢失,从而 Mami 仍有消灭 Charlotte 的可能. 你必须根据 Homura 告诉你的“糖果”和“药片”的能量的信息迅速告诉 Homura 这种情况的个数.

Input

第一行两个整数 n, k, 含义如题目描述.
接着第二行 n 个整数, 第 i 个数表示第 i 个糖果的能量.
第三行 n 个整数, 第 j 个数表示第 j 个药片 的能量.

Output

一个整数, 表示消灭 Charlotte 的情况个数.
答案可能会很大, 所以 mod (1 0^9 + 9)

Sample Input

4 2
5 35 15 45
40 20 10 30

Sample Output

4

Hint

正确的组合 (5-40, 35-20, 15-10, 45-30), (5-40, 45-20, 15-10, 35-30), (45-40,5-20, 15-10, 35-30) 以及 (45-40, 35-20, 15-10, 5-30)
【数据规模】
约定:给出的 2*n 个能量值两两不同
对于 10%的数据: 1<=n<=10
对于 40%的数据: 1<=n<=500
对于 100%的数据: 1<=n<=2000, 0<=k<=n
 
 
 
这题简直是又刷新我的三观
这题是湖北省省队互测的题目,难度已经是非常的大了
首先我们肯定要排序,然后接着一堆666操作就来了
首先我们要计算出一个nxt[i]数组表示在前 i 个数中有多少个数字是比a[i]要小的
我们计算出这个东西之后就可以定义一个状态f[i][j]了,这个状态描述的是前 i 对数字中,如果至少匹配 j 对的方案数
方程就是
 1 f[i][j]=(f[i-1][j]+f[i-1][j-1]*(nxt[i]-(j-1)))%mod 
为什么是这个样子的?因为我们显然只有选择或者不选择这两种情况,如果选择的话显然只能在前面nxt[i]个数里面选择,但是因为之前已经配对了j-1对,所以选择的数目就要少了很多
如果不选的更简单了,直接继承上一个状态就可以了
(注意,我们在这里只关心配对的数字方案数,至于其他的元素我们其实并不关心,这要到后面其实才能够说的清楚)
然后我们发现,因为我们忽略了其他元素,所以除开f[n][i]中 i 对之外,其实我们还有 n-i 对需要进行排列,这个的方案数其实是(n-i)!的方案数(两两配对固定一组可以证明)
所以我饿哦们其实可以设一个数组g[i]表示考虑n对包括其他无关不知道有没有配对元素(也就是至少i对元素)的方案数,那么我们又可以得到一个方程
 1 g[i]=f[n][i]*(n-i)!%mod 
然后我们的目标其实是求恰好k个的方案数,显然应该配对(n+k)/2个元素,但是我们其实记录的是至少i对的元素,显然我们就要容斥
对于一个 i 对配对来说,会包含 j (j>i)对,由于我们是恰好,所以我们就要在 j 对里面选择i个元素才是我们的方案数,显然这么下来就是C[i][j]次重复,我们就要逐个减掉 
所以我们设一个F[i]数组表示恰好有 i 对符合条件的数对,显然对于 i 来说会被前面的大于 i 的包含,所以减掉C[i][j]*F[j]就可以了
方程就是;
 1 F[i]=((g[i]-c[j][i]*F[j]%mod)%mod+mod)%mod; 
然后输出答案就可以咯
code:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 long long a[2003],b[2004],nxt[2004];
 6 const long long mod=1e9+9;
 7 long long c[3000][3000],jie[3000],n,k,f[3000][3000],g[3000],dp[3000];
 8 void pre(){
 9     c[0][0]=1;
10     jie[0]=1;
11     for(long long i=1;i<=n+1;i++){
12         c[i][i]=c[i][0]=1;
13         for(long long j=1;j<i;j++){
14             c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
15         }
16         jie[i]=jie[i-1]*i%mod;
17     //    cout<<jie[i]<<" ";
18     }
19 }
20 int main(){
21     cin>>n>>k;
22     pre();
23     for(long long i=1;i<=n;i++)cin>>a[i];
24     for(long long i=1;i<=n;i++)cin>>b[i];
25     sort(a+1,a+n+1);sort(b+1,b+n+1);
26     long long head=1;
27     f[0][0]=1;
28     for(long long i=1;i<=n;i++){
29         nxt[i]=head;
30         while(a[i]>b[head]&&head<=n){
31             nxt[i]=head;
32             head++;
33         }
34         f[i][0]=1;
35     }
36     for(long long i=1;i<=n;i++){
37         for(long long j=1;j<=n;j++){
38             f[i][j]=(f[i-1][j]+(f[i-1][j-1]*(nxt[i]-j+1))%mod)%mod;
39 //            cout<<f[i][j]<<" ";
40         }
41 //        cout<<endl;
42     }
43     if((k+n)&1){
44         cout<<0;
45         return 0;
46     }
47     k=k+n>>1;
48     for(long long i=n;i>=1;i--){
49         g[i]=f[n][i]*jie[n-i]%mod;
50         for(long long j=i+1;j<=n;j++){
51             g[i]=((g[i]-c[j][i]*g[j]%mod)%mod+mod)%mod;
52         }
53     }
54     for(int i=1;i<=n;i++)cout<<g[i]<<" ";
55     cout<<(g[k]+mod)%mod;
56     return 0;
57 }

over

posted @ 2018-10-06 16:10  saionjisekai  阅读(62)  评论(0编辑  收藏  举报