1. 程式人生 > >【BZOJ2339】[HNOI2011]卡農 組合數+容斥

【BZOJ2339】[HNOI2011]卡農 組合數+容斥

clu scan logs printf class 之前 include zoj mic

【BZOJ2339】[HNOI2011]卡農

技術分享

題解:雖然集合具有無序性,但是為了方便,我們先考慮有序的情況,最後將答案除以m!即可。

考慮DP。如果我們已經知道了前m-1個集合,那麽第m個集合已經是確定的了。因為內層集合的n個元素可以隨便出現,那麽總數就是A(2^n-1,m-1)。但是可能存在不合法的情況。

1.在前m-1個集合中,n個數出現的次數已經都是偶數了,那麽第m個集合為空,不合法,此時方案數為f[m-1]。
2.第m個集合與之前某個集合相同,那麽我們不考慮這兩個集合,剩下的方案數為f[i-2];該集合可能是第1...m-1個;該集合可能有2^n-1-(m-2)中情況。所以方案數為f[i-2]*(m-1)*(2^n-1-(m-2))

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const ll mod=100000007;
ll n,m,n2,c,m1;
ll ine[1000010],f[1000010];
int main()
{
	scanf("%lld%lld",&n,&m);
	ll i;
	ine[1]=1;
	for(i=2;i<=m;i++)	ine[i]=(mod-(mod/i)*ine[mod%i]%mod)%mod;
	for(n2=i=1;i<=n;i++)	n2=(n2<<1)%mod;
	n2=(n2-1+mod)%mod,c=1,f[0]=1,f[1]=0,m1=1;
	for(i=2;i<=m;i++)
	{
		c=c*(n2-i+2)%mod,m1=m1*ine[i]%mod;
		f[i]=((c-f[i-1]-f[i-2]*(n2-i+2)%mod*(i-1))%mod+mod)%mod;
	}
	printf("%lld",f[m]*m1%mod);
	return 0;
}

【BZOJ2339】[HNOI2011]卡農 組合數+容斥