3027: [Ceoi2004]Sweet
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 169 Solved: 82
[ Submit][ Status][ Discuss]
Description
John得到了n罐糖果。不同的糖果罐,糖果的种类不同(即同一个糖果罐里的糖果种类是相同的,不同的糖果罐里的糖果的种类是不同的)。第i个糖果罐里有 mi个糖果。John决定吃掉一些糖果,他想吃掉至少a个糖果,但不超过b个。问题是John 无法确定吃多少个糖果和每种糖果各吃几个。有多少种方法可以做这件事呢?
Input
从标准输入读入每罐糖果的数量,整数a到b
John能够选择的吃掉糖果的方法数(满足以上条件)
Output
把结果输出到标准输出(把答案模 2004 输出)
1<=N<=10,0<=a<=b<=10^7,0<=Mi<=10^6
Sample Input
2 1 3
3
5
Sample Output
9
设f[n]表示吃掉刚好n颗糖果的方案数,f[n]的母函数为
设ans[p]表示G[x] 0~p项的系数和,那么本题答案就是ans[b]-ans[a-1]
那么怎么求上面那公式前b项的系数和呢?
因为n其实很小,所以右边连乘可以直接2^n暴力每一项系数,对于当前第p项a[p]*x^p,左半部分要乘的组合数就为
注意模数不是质数,所以可能不存在逆元,一个解决方法是直接将模数先乘上分母(分母最大10!),最后再除掉
#include<stdio.h>
#define LL long long
LL mod, n, p[15], jc[15] = {1};
LL C(LL n, LL m)
{
LL i, ans = 1;
if(n<m)
return 0;
for(i=1;i<=m;i++)
ans = ans*(n-i+1)%mod;
return ans;
}
LL Sech(LL k)
{
LL i, j, now, f, ans = 0;
for(i=0;i<(1ll<<n);i++)
{
now = 0, f = 1;
for(j=0;j<=n-1;j++)
{
if(i&(1ll<<j))
{
now += p[j+1]+1;
f = -f;
}
}
ans = (ans+f*C(n+k-now, n)%mod+mod)%mod;
}
return ans;
}
int main(void)
{
LL a, b, i;
mod = 2004;
for(i=1;i<=10;i++)
jc[i] = jc[i-1]*i;
scanf("%lld%lld%lld", &n, &a, &b);
mod = mod*jc[n];
for(i=1;i<=n;i++)
scanf("%lld", &p[i]);
printf("%lld\n", (Sech(b)-Sech(a-1)+mod)%mod/jc[n]);
return 0;
}
/*
10 13523 463463
123124 23452 457457 123 234 346 23 634 12 5
*/