【codeforces 451E】Devu and Flowers

题目:Devu and Flowers

题意:

  有n个花坛,要选s支花,每个花坛有f[i]支花,同一个花坛的花颜色相同,不同花坛的花颜色不同,问可以有多少种组合。

解析:

  多重集组合数+ L u c a s Lucas Lucas定理+状压。
  直接上多重集组合数的公式就行了,这里由于 n ≤    20 n\leq\;20 n20,可以将状态压缩为二进制数,即枚举 x = 0 x=0 x=0~ 2 n − 1 2^n-1 2n1,若 x x x在二进制表示下共有 p p p位为1,分别是第 i 1 , i 2 , . . . . . . i p i_1,i_2,......i_p i1,i2,......ip位,则这个 x x x就代表公式中的 ( − 1 ) p C N + M − c i 1 − c i 2 − . . . . . . − c i p − p − 1 N − 1 (-1)^pC_{N+M-c_{i_1}-c_{i_2}-......-c_{i_p}-p-1}^{N-1} (1)pCN+Mci1ci2......cipp1N1
  特别的,若 x = 0 x=0 x=0则代表 C N + M − 1 N − 1 C_{N+M-1}^{N-1} CN+M1N1。并且为了防止爆 l o n g long long l o n g long long,可以通过 L u c a s Lucas Lucas定理取模解决。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int mod=1e9+7;
const int Max=20;
int n,m,ans;
int num[Max];

inline int ksm(int a,int b)
{
	int ans=1;
	a%=mod;
	while(b)
	{
	  if(b&1) ans=(ans*a)%mod;
	  b>>=1;
	  a=(a*a)%mod;
	}
	return ans;
}
inline int C(int n,int m)
{
	if(n>=0&&m>=0&&n>=m)
	{
	  int s1=1,s2=1;
	  for(int i=m-1;~i;i--)
	  {
	 	s1=s1*(n-i)%mod;
	 	s2=s2*(i+1)%mod;
	  }
	  return s1*ksm(s2,mod-2)%mod;
	}
	else return 0;
}
inline int Lucas(int n,int m)
{
	if(!m) return 1;
	return (C(n%mod,m%mod)*Lucas(n/mod,m/mod))%mod;
}

signed main()
{
	cin>>n>>m;
	for(int i=0;i<n;i++) cin>>num[i];
	for(int k=0;k<(1<<n);k++)
	{
	  int p=0,t=n+m;
	  for(int i=0;i<n;i++)
	  {
	  	if(!((1<<i)&k)) continue;
	  	t-=num[i],p++;
	  }
	  if(t-p-1<0) continue;  //注意特判
	  t-=p+1;
	  if(p&1) ans=(ans-Lucas(t,n-1))%mod;
	  else ans=(ans+Lucas(t,n-1))%mod;
	}
	cout<<(ans%mod+mod)%mod;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值