bzoj3028

题目链接:bzoj3028
题意:
承德汉堡:偶数个
可乐:0个或1个
鸡腿:0个,1个或2个
蜜桃多:奇数个
鸡块:4的倍数个
包子:0个,1个,2个或3个
土豆片炒肉:不超过一个。
面包:3的倍数个
你要用这些食物凑成n个,求方案数。
n<=10^500
题解:
这道题要用生成函数来做,我们把一件物品看做生成函数,我们可以用多项式来表示,i次项的系数表示这种物品凑出i个的方案数。我们就只需求出所有生成函数的卷积即可,当n<=100000时,我们可以用fft来解决这个问题,然而此题数据范围过大,我们考虑现将这些物品的卷积给化简,得生成函数为x/(1-x)^4。
x/(1-x)^4=x*(1+x+x^2+x^3+x^4+…..x^(无限))^4
=x*((1+x+x^2+x^3+x^4+…..x^(无限))^2)^2
=x*(1+2x+3x^2+4x^3+……x^(无限))^2
根据多项式乘法的定义
设A,B,C是3个多项式 F(A,I)表示多项式A中i次项的系数
若A*B=C
则F(C,X)=∑(F(A,K)*F(B,X-K)) {K=0….X}
设A=B=1+2x+3x^2+4x^3+……x^(无限)
那么F(C,N-1)就是我们要求的答案
(注:由于x*(1/(1-x)^4),外面乘了个x,所以我们求的是F(C,N-1)而不是F(C,N))
观察1+2x+3x^2+4x^3+……x^(无限)的性质可知:
F(A,X)=X+1 F(B,X)=X+1
那么F(C,N-1)=∑(F(A,K)*F(B,N-1-K)) {K=0….N-1}
=∑((K+1)*(N-1-K+1)) {K=0….N-1}
=∑((K+1)*(N-K))
=∑(K*N-K^2+N-K)
=(∑K*N)-∑(K^2)+∑(N-K)
=(N*N*(N-1)/2)-(N*(N-1)*(2N-1)/6)+(N(N+1)/2)
=(N(N^2+1)/2)-(N*(N-1)*(2N-1)/6)
=(N(N^2+3N+2)/6)
=N(N+1)(N+2)/6
最后我们用逆元把/6变成*1668即可。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <algorithm>
using namespace std;
char s[510];
const int mod=10007;
int n;
int ans;
int main(){
    freopen("3028.in","r",stdin);
    freopen("3028.out","w",stdout);
    scanf("%s",s+1);
    int l=strlen(s+1);
    for (int i=1;i<=l;i++) n=(n*10+s[i]-'0')%mod;
    ans=(((n*(n+1))%mod*(n+2))%mod*1668)%mod;
    printf("%d\n",ans);
    fclose(stdout);
    fclose(stdin);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值