bzoj 3622: 已经没有什么好害怕的了
3622: 已经没有什么好害怕的了
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1226 Solved: 584
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
4 2
5 35 15 45
40 20 10 30
5 35 15 45
40 20 10 30
Sample Output
4
HINT
输入的2*n个数字保证全不相同。
还有输入应该是第二行是糖果,第三行是药片
Source
把两个数组先排序。
设f[i][j] 为前i个a中选了j个于b匹配,且都比b大的方案数。
显然f[i][j] = f[i-1][j] + f[i-1][j-1] * (t[i] - j +1) ,其中t[i]表示a[i]比多少b大。
然后再设g[i]为a中 至少有 i对大于 b的方案数。
则g[i] = f[n][i] * (n-i)! ,因为除了选出的确定比b大的数,剩下的数可以随意排列。
然后我们再设f[i]为a中恰好有 i对大于 b的方案数。
组合计数一下,g[i] = Σ f[j] * C(j,i) ,组合数的权值就代表j对大的关系中有i对被dp的时候统计了。
反演一下, f[i]= Σ g[j] * C(j,i) *(-1)^(j-i)
#include<bits/stdc++.h> #define ll long long const int ha=1000000009; const int maxn=2005; using namespace std; int t[maxn],n,m,jc[maxn]; int f[maxn],ni[maxn],k; int a[maxn],b[maxn]; int g[maxn],h[maxn]; inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline void init(){ jc[0]=1; for(int i=1;i<=2000;i++) jc[i]=jc[i-1]*(ll)i%ha; ni[2000]=ksm(jc[2000],ha-2); for(int i=2000;i;i--) ni[i-1]=ni[i]*(ll)i%ha; } inline int C(int x,int y){ return jc[x]*(ll)ni[y]%ha*(ll)ni[x-y]%ha; } inline void dp(){ f[0]=1; for(int i=1;i<=n;i++) for(int j=t[i];j;j--) f[j]=add(f[j],f[j-1]*(ll)(t[i]-j+1)%ha); for(int i=0;i<=n;i++) g[i]=f[i]*(ll)jc[n-i]%ha; } inline void calc(){ int ans=0; for(int i=k,j=0;i<=n;i++,j^=1){ if(j) ans=add(ans,ha-g[i]*(ll)C(i,k)%ha); else ans=add(ans,g[i]*(ll)C(i,k)%ha); } printf("%d\n",ans); } int main(){ init(); scanf("%d%d",&n,&k); if(n&k&1){ puts("0"); return 0; } k=(n+k)>>1; for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=1;i<=n;i++) scanf("%d",b+i); sort(a+1,a+n+1),sort(b+1,b+n+1); for(int i=1;i<=n;i++){ t[i]=t[i-1]; while(t[i]<n&&b[t[i]+1]<=a[i]) t[i]++; } dp(); calc(); return 0; }
我爱学习,学习使我快乐