1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1123 Solved: 658
[ Submit][ Status]
Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s
Output
每次的方法数
Sample Input
3 2 3 1 10
1000 2 2 2 900
Sample Output
27
HINT
数据规模
di,s<=100000
tot<=1000
【题解】 一开始往DP想,可惜在想到容斥原理之前,先想到了生成函数,于是乎,开始了漫长的公式推导。
A=x^0+x^c[i]+x^(c[i]*2)......+x^(c[i]*d[i]);
(x^c[i])A=x^c[i]+x^(c[i]*2).....+x^(c[i]*d[i]+c[i]);
(x^c[i]-1)A=x^(c[i]*d[i]+c[i])-x^0;
A=[x^(c[i]*d[i]+c[i])-x^0]/(x^c[i]-1);
1/(x^c[i]-1)=-[x^0+x^c[i]+x^(c[i]*2)+x^(c[i]*3)....];
于是:
ans= (x^(c[1]*d[1]+c[1])-1)*(x^(c[2]*d[2]+c[2])-1)*(x^(c[3]*d[3]+c[3])-1)*(...) 中 x^s 的系数* DP;
Dp=1/(x^c[1]-1) * 1/(x^c[2]-1)... 这里的Dp[i] 可以通过4*100000 的效率预处理出来;{Dp[i] 表示如果无限使用每一个硬币凑出i 的方案数;}
所以就可以求解了。
至于如何用母函数求出系数这类问题,先去做 http://codeforces.com/contest/451/problem/E 。
#include<cstdio>
#include<cstdlib>
#define Ms 1000100
#define LL long long
int d[8],tot,s,c[8]; LL f[Ms],ans,v[8];
void work(int x,LL y,int ff)
{
if(y>s)return;
if(x==5)
{
ans+=ff*f[s-y];return;
}
work(x+1,y,-ff);
work(x+1,y+v[x],ff);
}
int main()
{
scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot);
f[0]=1;for(int i=1;i<=4;i++)for(int j=c[i];j<=Ms;j++)f[j]+=f[j-c[i]];
for(;tot--;)
{
for(int i=1;i<=4;i++)scanf("%d",&d[i]);
scanf("%d",&s);
for(int i=1;i<=4;i++)v[i]=(LL)c[i]*d[i]+c[i];
ans=0;work(1,0,1);printf("%lld\n",ans);
}
return 0;
}