N个盒子,每个盒子里面有一种颜色的花,数量为si,N个盒子里花的颜色各不相同,但同一个盒子里面的花认为是相同的,现在需要选出K朵花,有多少种不同的方案?由于结果很大,输出Mod 1000000007的结果即可。
例如:3个盒子,花的数量分别为1 3 2,需要选出5朵花,那么可以有如下3种方案:{1, 2, 2}, {0, 3, 2}, {1, 3, 1}。
Input
第1行:两个数N, K。N为盒子的数量,K为需要的花朵的数量(1 <= N <= 20, 1 <= K <= 10^18) 第2 - N + 1行:每行1个数,对应盒子中花朵的数量Si(1 <= Si <= 10^16)
Output
输出方案的数量Mod 1000000007。
Input示例
3 5 1 3 2
Output示例
3
思路:
1.转换为求G(x)=(1+x+x^2+...+x^s1)*(1+x+x^2+...+x^s2)*...*(1+x+x^2+...+x^sn)
中x^k的系数
2.在每个盒子花无限的情况下ans=C(k+n-1,n-1)
ans等于a1+a2+...+an=k这个n元一次方程的解的个数,ai指x的贡献值
不理解可以看下下面这篇文章
https://wenku.baidu.com/view/843aff00bed5b9f3f90f1c25.html
3.因为有s作为限制,所以我们可以枚举对于第i个盒子来说,选择花的个数超出si的方案数, (pass:包括其他盒子超出个数的情况,所以得用容斥)方法数即为C(k+n-1-s1-1,n-1),
用插板,si+1是因为考虑可以取0个的情况
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
typedef long long LL;
const LL MOD=1000000007;
using namespace std;
LL s[30];
LL quick_pow(LL a,LL b)
{
LL c=1;
while(b)
{
if(b&1)
c=(a*c)%MOD;
a=(a*a)%MOD;
b>>=1;
}
return c;
}
LL inv(LL n)
{
return quick_pow(n,MOD-2);
}
LL C(LL n,LL m)
{
if(n<m)
return 0;
LL a=1,b=1;
for(LL i=0;i<m;i++)
{
a=a*(n-i)%MOD;
b=b*(m-i)%MOD;
}
return (a*inv(b))%MOD;
}
LL Lucas(LL n, LL m)
{
return m?Lucas(n/MOD,m/MOD)*C(n%MOD,m%MOD)%MOD:1;
}
int main()
{
LL n,k,ans;
while(scanf("%lld%lld",&n,&k)!=-1)
{
for(int i=0;i<n;i++)
scanf("%lld",&s[i]);
ans=0;
for(int i=0;i<(1<<n);i++)
{
LL cnt=0,sum=k;
for(int j=0;j<n;j++)
{
if(i&(1<<j))
{
cnt++;
sum-=s[j]+1;
}
}
if(sum<0)
continue;
if(cnt&1)
ans=(ans-Lucas(sum+n-1,n-1)+MOD)%MOD;
else
ans=(ans+Lucas(sum+n-1,n-1)+MOD)%MOD;
}
printf("%lld\n",(ans+MOD)%MOD);
}
return 0;
}
在26号凌晨终于写完该24号写的博客,明天将这个题目再吸收下>.<,补校赛题,两篇博客,加油呀!
--------------2018/1/26