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

bzoj-1042 硬币购物

时间:2015-07-30 11:20:19      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:bzoj   容斥原理   背包dp   

题意:

有四种面值的硬币ci,进行tot次购物;

每次购物每种硬币有di个,问买s元的物品有几种方法;


题解:

硬币面值只有四种,可以猜测到算法复杂度不会很大;

普通的背包无法限制di个这个条件;

而将di个硬币拆开复杂度无法承受,并且一样难以统计方案;

所以考虑容斥原理简化问题;

去掉di的限制,令f[x]表示四种硬币购买x元的物品有几种方法;

这个f数组可以在O(4*10^5)的复杂度处理;

然后反向考虑,如果硬币1超过d1个的限制的时候,f[s-c1*(d1+1)]恰好为方案数;

用总方案减去这些方案数,容斥原理搞一下就好了;

总感觉自己的容斥有点奇怪。。不过反正乱搞能AC= =;

似乎要开long long;


代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100001
using namespace std;
typedef long long ll;
int c[4],d[4];
ll f[N],ans;
void slove(int now,int val)
{
	int k=0;
	for(int i=0;i<4;i++)
	{
		if(now&(1<<i))
		{
			k^=1;
			val-=c[i]*(d[i]+1);
		}
	}
	if(val<0)	return ;
	ans+=(k?-1:1)*f[val];
}
int main()
{
	int n,m,i,j,k;
	for(i=0;i<4;i++)
		scanf("%d",c+i);
	scanf("%d",&n);
	f[0]=1;
	for(i=0;i<4;i++)
	{
		for(j=0;j<N;j++)
			f[j+c[i]]+=f[j];
	}
	for(i=1;i<=n;i++)
	{
		for(j=0;j<4;j++)
			scanf("%d",d+j);
		scanf("%d",&m);
		ans=0;
		for(j=0;j<16;j++)
			slove(j,m);
		printf("%lld\n",ans);
	}
	return 0;
}



bzoj-1042 硬币购物

标签:bzoj   容斥原理   背包dp   

原文地址:http://blog.csdn.net/ww140142/article/details/47145937

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