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;
}