[BZOJ3028]食物
Description:
明明这次又要出去旅游了,和上次不同的是,他这次要去宇宙探险!我们暂且不讨论他有多么NC,他又幻想了他应该带一些什么东西。理所当然的,你当然要帮他计算携带N件物品的方案数。他这次又准备带一些受欢迎的食物,如:蜜桃多啦,鸡块啦,承德汉堡等等当然,他又有一些稀奇古怪的限制:每种食物的限制如下:
承德汉堡:偶数个
可乐:0个或1个
鸡腿:0个,1个或2个
蜜桃多:奇数个
鸡块:4的倍数个
包子:0个,1个,2个或3个
土豆片炒肉:不超过一个。
面包:3的倍数个
注意,这里我们懒得考虑明明对于带的食物该怎么搭配着吃,也认为每种食物都是以‘个’为单位(反正是幻想嘛),只要总数加起来是N就算一种方案。因此,对于给出的N,你需要计算出方案数,并对10007取模。
Hint:
输入一个数字N,\(1<=n<=10^{500}\)
Solution:
生成函数入门题,具体的推导过程:
首先写出生成函数:
等比数列求和,化简:
然后乘起来:
所以答案就是次数为n的项的系数,即C(n+2,3)
虽然n很大但模数很小,可以lucas搞一下
#include<bits/stdc++.h>
using namespace std;
const int p=10007;
int inv[p+5],jc[p+5];
char s[505];
int main()
{
scanf("%s",s); int n=0,len=strlen(s);
inv[0]=inv[1]=jc[0]=jc[1]=1;
for(int i=2;i<=p;++i) inv[i]=(p-p/i)%p*inv[p%i]%p,jc[i]=jc[i-1]*i%p;
for(int i=2;i<=p;++i) inv[i]=inv[i]*inv[i-1]%p;
for(int i=0;i<len;++i)
n=((n*10)+s[i]-'0')%p;
n=(n+2)%p;
printf("%d\n",jc[n]*inv[3]%p*inv[n-3]%p);
return 0;
}