bzoj 3027: [Ceoi2004]Sweet(母函数+组合数)

3027: [Ceoi2004]Sweet

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 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
*/

  • 1
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论

打赏作者

Jaihk662

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值