码迷,mamicode.com
首页 > 其他好文 > 详细

【bzoj1042】【HAOI2008】【硬币购物】【dp】

时间:2015-08-28 21:40:33      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:

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

题解:因为数据范围比较大,所以考虑一下其他的方法。

           然后就可以容斥一下。。

           先处理出在没有硬币个数限制的情况下买价格为i的物品的方案数,记为f[i];

           最后     ans=没有限制的方案数-至少有一个超过限制的方案数+至少有两个超过限制的方案数-至少有三个超过限制的方案数+全部超过限制的方案数。

            对于超过限制的方案数的求法,我们可以这么考虑。先强制这超过限制的硬币选d+1个,看一下总和(temp)是不是会超过s,如果超过答案为0,否则答案为f[s-temp];

             时间复杂度 O(s+tot);

#include<cstdio>
#include<cstring>
#include<iostream>
#define N 100010
using namespace std;
int n,s,c[5],d[5];
long long f[N],ans;
long long cal(int x,int y,int p,int q)
{
	int temp(0);
	temp=c[x]*(d[x]+1)+c[y]*(d[y]+1)+c[p]*(d[p]+1)+c[q]*(d[q]+1);
	return (temp>s?0:f[s-temp]);
}
int main()
{
	for(int i=1;i<=4;i++) scanf("%d",&c[i]);
	scanf("%d",&n);
	f[0]=1;
	for(int j=1;j<=4;j++)
		for(int i=c[j];i<N;i++)
			f[i]+=f[i-c[j]];
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=4;i++)scanf("%d",&d[i]);
		scanf("%d",&s);
		ans=cal(0,0,0,0);
		ans-=cal(1,0,0,0);ans-=cal(2,0,0,0);
		ans-=cal(3,0,0,0);ans-=cal(4,0,0,0);
		ans+=cal(1,2,0,0);ans+=cal(1,3,0,0);
	    ans+=cal(1,4,0,0);ans+=cal(2,3,0,0);
		ans+=cal(2,4,0,0);ans+=cal(3,4,0,0);
        ans-=cal(1,2,3,0);ans-=cal(1,2,4,0);
		ans-=cal(1,3,4,0);ans-=cal(2,3,4,0);
		ans+=cal(1,2,3,4);
		printf("%lld\n",ans);
	}
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

【bzoj1042】【HAOI2008】【硬币购物】【dp】

标签:

原文地址:http://blog.csdn.net/sunshinezff/article/details/48056465

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!