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

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

题意:

给n个数Ai,n个数Bi,将Ai中的数与Bi中的数配对,求配对Ai比Bi大的比Bi比Ai大的恰好有k组的方案数。n,k≤2000

题解:

蒟蒻太弱了只能引用神犇题解

我们将两个读入的数组排序,令 next[i] 表示最大的 j 满足 A[i]>B[j],令f[i][j]表示枚举到第i个A时,有j组A>B,但剩下的情况是不考虑的,则f[i][j]=f[i-1][j]+f[i-1][j-1]*(next[i]-j+1)。但若把 f[n][s] 直接输出会WA因为会有这种情况出现:

a1,a2,a3

b1,b2,b3

a1>b1  a2>b2  a3>b3

那么((a1,b1),(a2,b2),a3不明)和((a1,b1),(a3,b3),a2不明)就会被视为两种答案,可见我们要求出的是 f’[n][s] 表示n个A,有s组A>B,剩下的都是B>A

这里就要用容斥了

f'[n][i]=f[n][i]*(n-i)!-sigma(j,i+1,n)f'[n][j]*C[j][i]

(n-i)!是枚举后面 n-i 可能的方案,f‘[n][j]*C(j, i) 表示 f[n][i] 中实际有 j 组B>A却被计入f[n][i]的数量

f'[n][s]就是答案了,总时间复杂度为 O(n2)

C(j,i)要递推,不然要溢出。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define dec(i,j,k) for(int i=j;i>=k;i--)
 6 #define maxn 2100
 7 #define mod 1000000009
 8 #define ll long long
 9 using namespace std;
10 
11 int s[maxn],p[maxn],next[maxn],n,k; ll f1[maxn][maxn],f2[maxn],C[maxn][maxn],P[maxn];
12 inline int read(){
13     char ch=getchar(); int f=1,x=0;
14     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
15     return f*x;
16 }
17 int main(){
18     n=read(); k=read(); if((n-k)&1){printf("0"); return 0;} k=((n-k)>>1)+k;
19     inc(i,1,n)s[i]=read(); inc(i,1,n)p[i]=read(); sort(s+1,s+n+1); sort(p+1,p+n+1);
20     int l=1; inc(i,1,n){while(p[l]<s[i]&&l<=n)l++; next[i]=l-1;}
21     f1[0][0]=1; inc(i,1,n){f1[i][0]=1; inc(j,1,n)f1[i][j]=(f1[i-1][j]+f1[i-1][j-1]*(ll)max(next[i]-j+1,0)%mod)%mod;}
22     P[0]=1; inc(i,1,n)P[i]=P[i-1]*(ll)i%mod;
23     inc(i,0,n){C[i][0]=1; inc(j,1,i)C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;}
24     dec(i,n,k){
25         f2[i]=0; inc(j,i+1,n)f2[i]=(f2[i]+f2[j]*C[j][i]%mod)%mod;
26         f2[i]=f1[n][i]*P[n-i]%mod-f2[i]; if(f2[i]<0)f2[i]+=mod;
27     }
28     printf("%lld",f2[k]); return 0;
29 }

 

20160610

posted @ 2016-08-16 23:00  YuanZiming  阅读(314)  评论(0编辑  收藏  举报