BZOJ 1042

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 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

1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900

Sample Output

4
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
#include
#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;
}

你可能感兴趣的:(BZOJ)