BZOJ 1042 HAOI 2008 硬币购物 容斥原理

题目大意:给出4个硬币的价值和个数限制,求有多少种方法凑成S块钱。


思路:很巧妙的一种想法,用到了4这个非常小的数字。我们可以先不管每个硬币的个数限制,然后跑一次完全背包。之后把不符合的情况去除就行了。方法是,先减去一种硬币超限的数目,然后加上两种硬币超限的数目,然后减去三种硬币超限的数目,然后加上四种硬币超限的个数。当然代码就很丑了。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
#define P(i) (c[i] * (l[i] + 1))
using namespace std;
 
int c[5],l[5],s;
int cnt;
long long f[MAX],ans;
 
int main()
{
    for(int i = 1; i <= 4; ++i)  
        scanf("%d",&c[i]);
    cin >> cnt;
    for(int i = 1; i <= cnt; ++i) {
        for(int j = 1; j <= 4; ++j)
            scanf("%d",&l[j]);
        scanf("%d",&s);
        memset(f,0,sizeof(f));
        f[0] = 1;
        for(int _i = 1; _i <= 4; ++_i)
            for(int j = c[_i]; j <= s; ++j)
                f[j] += f[j - c[_i]];       
        ans = f[s];
        for(int _i = 1; _i <= 4; ++_i)   
            if(s - P(_i) >= 0)
                ans -= f[s - P(_i)];
        if(s - P(1) - P(2) >= 0) ans += f[s - P(1) - P(2)];
        if(s - P(2) - P(3) >= 0) ans += f[s - P(2) - P(3)];
        if(s - P(3) - P(4) >= 0) ans += f[s - P(3) - P(4)];
        if(s - P(2) - P(4) >= 0) ans += f[s - P(2) - P(4)];
        if(s - P(1) - P(3) >= 0) ans += f[s - P(1) - P(3)];
        if(s - P(1) - P(4) >= 0) ans += f[s - P(1) - P(4)];
        if(s - P(1) - P(2) - P(3) >= 0)  ans -= f[s - P(1) - P(2) - P(3)];
        if(s - P(2) - P(3) - P(4) >= 0)  ans -= f[s - P(2) - P(3) - P(4)];
        if(s - P(1) - P(3) - P(4) >= 0)  ans -= f[s - P(1) - P(3) - P(4)];
        if(s - P(1) - P(2) - P(4) >= 0)  ans -= f[s - P(1) - P(2) - P(4)];
        if(s - P(1) - P(2) - P(3) - P(4) >= 0)   ans += f[s - P(1) - P(2) - P(3) - P(4)];
        printf("%lld\n",ans);
    }
    return 0;
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值