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

5 篇文章 0 订阅
4 篇文章 0 订阅

题目概述

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值