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