【bzoj 1042】 硬币购物 【HAOI2008】

Description

  硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买s
i的价值的东西。请问每次有多少种付款方法。

Input

  第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

Output

  每次的方法数

Sample Input

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

Sample Output

4
27

对于这道题,首先如果没有d_{i}的限制,那么只要用一个类似于背包的DP就可以在O(s)的时间复杂度下求出答案,设这样求出的总和为s的方案数为F_{s},那么运用容斥原理可以得到\tiny ans=F_{s}-\sum F_{s-c_{i}(d_{i}+1)}+\sum \sum F_{s-c_{i}(d_{i}+1)-c_{j}(d_{j}+1)}-\sum \sum \sum F_{s-c_{i}(d_{i}+1)-c_{j}(d_{j}+1)-c_{k}(d_{k}+1)}+F_{s-c_{1}*(d_{1}+1)-c_{2}*(d_{2}+1)-c_{3}*(d_{3}+1)-c_{4}*(d_{4}+1)},下面是程序:

#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=100005;
ll f[N]={1};
int c[4],d[4];
void dfs(int x,int k,int now,ll &ans){
	if(now<0){
		return;
	}
	if(x==4){
		ans+=k&1?-f[now]:f[now];
		return;
	}
	dfs(x+1,k+1,now-c[x]*(d[x]+1),ans);
	dfs(x+1,k,now,ans);
}
int main(){
	int i,j,t,s;
	ll ans;
	for(i=0;i<4;i++){
		scanf("%d",&c[i]);
	}
	scanf("%d",&t);
	for(i=0;i<4;i++){
		for(j=c[i];j<=100000;j++){
			f[j]+=f[j-c[i]];
		}
	}
	while(t--){
		for(i=0;i<4;++i){
			scanf("%d",&d[i]);
		}
		scanf("%d",&s);
		ans=0;
		dfs(0,0,s,ans);
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tlecoce/article/details/81322212