bzoj 3622: 已经没有什么好害怕的了

3622: 已经没有什么好害怕的了

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1226  Solved: 584
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

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

  

posted @ 2018-03-08 11:44  蒟蒻JHY  阅读(315)  评论(0编辑  收藏  举报