Codeforces 451E Devu and Flowers 容斥原理暴力+Lucas定理

点击打开链接

题意:n个box,n<=20,每个盒子有fi朵花,fi<=1e12,同一个box的花无区别,某个盒子选的数量不同就算不同方案,问选S朵花方案数?S<=1e14

若盒子中花无限答案显然为 x1+x2+..xn=S 的解集个数C(n+S-1,n-1) (yi=xi+1,n+S个1,n+S-1个空隙中选n-1个)

现在多了限制fi,若某个xi>fi 则从S先抽掉f[i]+1个,方案数为C(S-(f[i]+1)+n-1,n-1) ,运用容斥扣掉至少有一个xi>fi的方案数

n<=20 1表示xi>fi,用二进制数表示暴力表示2^n种情况,大组合数取模用了Lucas定理C(n,m)%p = C(n/p,m/p) * C(n%p,m%p) %p 

//plus:也可以用母函数来做

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+20;
const ll mod=1e9+7;
ll n,s,f[N],fact[N];
void preCalc()
{
	fact[0]=1;
	for(ll i=1;i<=100;i++)
		fact[i]=(fact[i-1]*i)%mod;
}
ll powmod(ll a,ll b,ll m)
{
	ll s=1;
	while(b)
	{
		if(b&1)
			s=(s%mod*a%mod)%m;
		a=(a%mod*a%mod)%m;	
		b>>=1;
	}
	return s;
}
ll inverse(ll n,ll p)//逆元 
{
	return powmod(n,p-2,p);
}
ll C(ll n,ll k,ll p)
{
	//C(n,k)%p n为大数,用Lucas定理 
	ll ans=1;
	for(ll i=n-k+1;i<=n;i++)
		ans=((ans%mod)*(i%mod))%mod;
	return (ans*inverse(fact[k],mod)%mod)%mod;
}
ll Lucas (ll n , ll m , ll p) {
        return m == 0 ? 1 : 1ll*C (n%p , m%p , p) * Lucas (n/p , m/p , p) %  p ;
}
int main()
{
	preCalc();
	while(cin>>n>>s)
	{
		ll ans=0;
		for(int i=0;i<n;i++)
			scanf("%I64d",&f[i]);
		//O(N*2^N)
		for(ll i=0;i<(1<<n);i++)//
		{
			ll S=s,cnt=0;
			for(ll j=0;j<=n;j++)
			{
				if(i&(1<<j))//xj>fj 
					S-=f[j]+1,cnt++;
			}
			if(S<0) continue;
			ll res=Lucas(S+n-1,n-1,mod);
			if(cnt%2)//-(奇数个为正)
				res*=-1; 
			ans=(ans+res+mod)%mod;
		}
		cout<<ans<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值