zoukankan      html  css  js  c++  java
  • 【题解】已经没有什么好害怕的了

    二项式反演的入门题,来写写理解。

    已经没有什么好害怕的了

    ( ext{Solution:})

    题目大意:给定两个互不相同的数列 (a,b,) 令他们两两配对,求 (a>b) 的数量恰好比 (b>a) 的数量多 (k) 的方案数。

    首先观察到如果满足这个条件那么其对数必然为 (frac{n+k}{2}) 个。所以可以把 (n+k) 是奇数的情况去掉。

    考虑,如果我们直接设 (f[i][j]) 为前 (i) 个糖果恰好有 (j) 对大于另一种的,如何转移?

    第一种是第 (i) 个糖果形成了符合条件的。观察一下,两个数列不单调?先排完序再继续考虑。

    如果说需要形成第一种情况,那有多少种是可以配对的?

    但是我们发现,如果这样假设,对应另一种的情况有多少对是不明确的。所以无法准确计算。

    那么假设 (f[i][j]) 表示前 (i) 个选择了 (j) 对满足条件的方案数?

    但我们还是需要得知前面的点有多少对凑成了另一种情况的点。同样不好求。

    考虑另一种思路:设 (f[i][j]) 表示前 (i) 个,至少(j) 对是第一种情况。换句话说,我钦定了 (j) 对满足条件,而其他的还没有配对的方案数。

    由于这里的定义是至少,所以其他的没有被钦定的点就可以随便排列。

    先让其他点不匹配,直接把 (f) 求出来。那么 (f[i][j] imes (i-j)!) 就是方案数了。

    由于其他点没有钦定,所以一定还有 (i-j) 种可以匹配。如果不匹配就直接放着就好了。

    所以 (f[i][j]=cnt_i imes f[i-1][j-1]+f[i-1][j].)

    考虑如何求出题目要求的 恰好 情况:用二项式反演。

    容易发现,恰好的情况是可以被至少来容斥出来的。有:

    [f(i)=sum_{j=i}^n (-1)^{j-i} imes inom{j}{i} imes g(j) ]

    容斥原理,或者叫做 二项式反演

    于是我们再做一遍二项式反演即可。

    一些细节:如果在 (g) 数组上直接反演,枚举的下标记得从 (i+1) 开始,因为你已经拿到了原来的值了,再加就重复了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=3e3+10;
    const int mod=1e9+9;
    inline int Add(int x,int y){return (x+y)%mod;}
    inline int Mul(int x,int y){return 1ll*x*y%mod;}
    inline int Dec(int x,int y){return (x-y+mod)%mod;}
    inline int Max(int x,int y){return x>y?x:y;}
    inline int Min(int x,int y){return x<y?x:y;}
    inline int Abs(int x){if(x<0)x=-x;return x;}
    inline int qpow(int x,int y){
    	int res=1;
    	while(y){
    		if(y&1)res=Mul(res,x);
    		x=Mul(x,x);y>>=1;
    	}
    	return res;
    }
    
    int f[N][N];
    int g[N];
    int inv[N],fac[N];
    int n,k,a[N],b[N];
    inline int C(int x,int y){
    	if(x<y)return 0;
    	return Mul(fac[x],Mul(inv[y],inv[x-y]));
    }
    void predo(){
    	fac[0]=1;
    	for(int i=1;i<=n;++i)fac[i]=Mul(fac[i-1],i);
    	inv[n]=qpow(fac[n],mod-2);
    	for(int i=n;i;--i)inv[i-1]=Mul(inv[i],i);
    }
    inline int getpos(int x){
    	int l=1,r=n;
    	int ans=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(b[mid]<x)ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ans;
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	scanf("%d%d",&n,&k);
    	if((n+k)&1){
    		puts("0");
    		return 0;
    	}
    	predo();
    	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=0;i<=n;++i)f[i][0]=1;
    	for(int i=1;i<=n;++i){
    		int num=getpos(a[i]);
    		for(int j=1;j<=i;++j){
    			f[i][j]=Add(f[i][j],Add(Mul(f[i-1][j-1],Max(num-j+1,0)),f[i-1][j]));
    		}
    	}
    	for(int i=1;i<=n;++i)g[i]=f[n][i];
    	for(int i=1;i<=n;++i)g[i]=Mul(g[i],fac[n-i]);
    	int P=(n+k)/2;
    	for(int i=P+1;i<=n;++i){
    		g[P]=Add(g[P],Mul(Mul(qpow(mod-1,i-P),C(i,P)),g[i]));
    	}
    	printf("%d
    ",g[P]);
    	return 0;
    }
    
  • 相关阅读:
    Visual Studio 2005 ReportViewer 自适应报表大小显示
    【Vegas原创】SharePoint 503 Service Unavailable Error解决方法
    【Vegas改编】用C#实现浏览文件夹功能
    【Vegas2010】最后的g.cn
    【Vegas原创】SQL Server游标的经典使用
    命名规范(变量、控件)
    【Vegas原创】outlook发送时,报550 5.7.1 client does not have permissions to send as this sender解决方法
    【Vegas原创】Winform中使用MaskedTextBox制作IP地址输入框
    【Vegas原创】Apache2.2 + PHP5.3.2 + Oracle 10g配置
    IT职涯路
  • 原文地址:https://www.cnblogs.com/h-lka/p/15273289.html
Copyright © 2011-2022 走看看