您的位置:首页 > 其它

【背包+容斥】BZOJ1042(HAOI2008)[硬币购物]题解

2017-10-31 10:05 190 查看

题目概述

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

解题报告

直接背包会TLE,但由于只有 4 种硬币,所以……

所以好难啊!根据容斥,答案为:价值恰好为 s 但硬币数不受限制的方案 − 第一枚硬币超过限制其他硬币不受限制的方案 − 第二枚硬币超过限制其他硬币不受限制的方案 ⋯ + 第一枚第二枚硬币超过限制其他硬币不受限制的方案 ⋯

然后容斥的模型就出来了,但是要如何求出每种情况的方案?首先先用背包求出价值恰好为 i 但硬币数不受限制的方案 f[i] ,则如果第一枚硬币超过限制,说明第一枚硬币至少放 d1+1 个,其他不受限制,那么方案就是 f[s−(d1+1)s1] 。别的情况同理。

示例程序

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxv=100000;

int te,w[4],s[4],v;LL f[maxv+5],ans;

void Dfs(int st,int tot=0,int now=v)
{
if (st==4) {if (tot&1) ans-=f[now]; else ans+=f[now];return;}
if ((s[st]+1)*w[st]<=now) Dfs(st+1,tot+1,now-(s[st]+1)*w[st]);
Dfs(st+1,tot,now);
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
scanf("%d%d%d%d",&w[0],&w[1],&w[2],&w[3]);f[0]=1;
for (int i=0;i<4;i++)
for (int j=w[i];j<=maxv;j++)
f[j]+=f[j-w[i]];
for (scanf("%d",&te);te;te--)
{
scanf("%d%d%d%d%d",&s[0],&s[1],&s[2],&s[3],&v);
ans=0;Dfs(0);printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: