BZOJ 1042: [HAOI2008]硬币购物

博客介绍了BZOJ 1042题目的内容,这是一个关于硬币购物的问题,涉及4种不同面值的硬币和各自的限制数量。由于使用多重背包算法会导致超时,作者提出了使用完全背包算法配合容斥原理来解决。通过设置f[i]表示价值i的支付方案数,并利用转移方程f[i]=σ(f[i-cj])进行计算,再对每种硬币应用容斥原理处理硬币限制,以找到所有可能的支付方式。
摘要由CSDN通过智能技术生成

题目地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1042

题目大意:4种硬币,面值分别为c1,c2,c3,c4,每种硬币分别有d1,d2,d3,d4枚,买价值为s的东西,有几种付款方法。

算法讨论:

        由于做多重背包会超时,考虑其他算法。

        首先做完全背包,设f[i]表示面值为i的方案数,转移方程为f[i]=sigma(f[i-cj])。

        然后对4种硬币进行容斥,强制某些硬币超过限制,取di+1枚,对剩余的硬币进行分配。

Code:

#include <cstdio>

#define N 100000

using namespace std;

bool v[5];
int T,s,c[5],d[5];
long long ans,f[N+10];

inline void dp(){
	f[0]=1;
	for (int i=1;i<=4;++i)
		for (int j=0;j<=100000-c[i];++j) f[j+c[i]]+=f[j];
}

void dfs(int k,int cnt){
	if (k>4){
		long long t=s;
		for (int i=1;i<=4;++i)
			if (v[i]) t-=(long long)(d[i]+1)*c[i];
		if (t>=0) if (cnt&1) ans-=f[t];else ans+=f[t];
		return;
	}
	v[k]=0;
	dfs(k+1,cnt);
	v[k]=1;
	dfs(k+1,cnt+1);
}

int main(){
	#ifndef ONLINE_JUDGE
	freopen("1042.in","r",stdin);
	freopen("1042.out","w",stdout);
	#endif
	for (int i=1;i<=4;++i) scanf("%d",&c[i]);
	scanf("%d",&T);
	dp();
	while (T--){
		for (int i=1;i<=4;++i) scanf("%d",&d[i]);
		scanf("%d",&s);
		ans=0;
		dfs(1,0);
		printf("%lld\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值