• 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
    ",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;
    }
    

      

  • 相关阅读:
    自己写的一个ASP.NET服务器控件Repeater和GridView分页类
    c#Udp分包组包方法
    利用反射写的,可以插件的俄罗斯方块
    冰之随笔一(c#反射、特性)
    Socket的简单例子
    HTTP状态码
    C# WebService 基础实例
    Win7上IIS发布网站系统部署项目
    FileUpload 简单上传+小预览
    .net 验证码
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8527508.html
Copyright © 2020-2023  润新知