BZOJ-1042: [HAOI2008]硬币购物 (背包DP+容斥原理)

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2888  Solved: 1777
[Submit][Status][Discuss]

Description

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

Input

  第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

Output

  每次的方法数

Sample Input

1 2 5 10 2

3 2 3 1 10

1000 2 2 2 900

Sample Output

4

27

HINT

Source

刚开始看题卧槽这不是傻逼多重背包嘛 _(:зゝ∠)_ 然后突然想起来这个绝逼超时,不用看数据范围都知道 _(:зゝ∠)_  正解是背包+容斥原理,先用完全背包求出每种钱有无数个的方案数,然后那f[s]-铁定超过范围的方案数,铁定超过范围的方案数就是|∪每种钱超过范围的方案| 这个用容斥原理可以解决

laj的code中式子第一项f[s]是dfs中在y=0的时候加上的f[sum]

 1 #include "bits/stdc++.h"
 2 using namespace std;
 3 typedef long long LL;
 4 const int MAX=1e5+5;
 5 LL c[5],d[5],s,t,f[MAX],ans;
 6 void dfs(LL x,LL y,LL sum){
 7     if (sum<0) return;
 8     if (x>4){
 9         if (y&1) ans-=f[sum];
10         else ans+=f[sum];
11         return;
12     }
13     dfs(x+1,y,sum),dfs(x+1,y+1,sum-(d[x]+1)*c[x]);
14 }
15 int main(){
16     freopen ("shopping.in","r",stdin);freopen ("shopping.out","w",stdout);
17     LL i,j;
18     scanf("%lld%lld%lld%lld%lld",c+1,c+2,c+3,c+4,&t);
19     for (i=f[0]=1;i<=4;i++)
20         for (j=c[i];j<MAX;j++)
21             f[j]+=f[j-c[i]];
22     while (t--){
23         scanf("%lld%lld%lld%lld%lld",d+1,d+2,d+3,d+4,&s);
24         ans=0;
25         dfs(1,0,s);
26         printf("%lld\n",ans);
27     }
28     return 0;
29 }
时间: 2024-10-11 01:22:47

BZOJ-1042: [HAOI2008]硬币购物 (背包DP+容斥原理)的相关文章

【bzoj1042】[HAOI2008]硬币购物 背包dp+容斥原理

题目描述 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. 输入 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000 输出 每次的方法数 样例输入 1 2 5 10 2 3 2 3 1 10 1000 2 2 2 900 样例输出 4 27 题解 背包dp+容斥原理 考虑没有硬币个数限制,那么本题显然是完全

[BZOJ 1042] [HAOI2008] 硬币购物 【DP + 容斥】

题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案. 为了避免重复的方案被转移,所以我们以硬币种类为第一层循环,这样阶段性的增加硬币. 一定要注意这个第一层循环要是硬币种类,并且初始 f[0] = 1. f[0] = 1; for (int i = 1; i <= 4; ++i) { for (int j = B[i]; j <= MaxS; +

bzoj 1042: [HAOI2008]硬币购物 dp+容斥原理

题目链接 1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1706  Solved: 985[Submit][Status][Discuss] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3

[Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥

题面 传送门:https://www.luogu.org/problemnew/show/P1450 Solution 这是一道很有意思的在背包里面做容斥的题目. 首先,我们可以很轻松地想到暴力做背包的做法. 就是对于每一次询问,我们都做一次背包. 复杂度O(tot*s*log(di)) (使用二进制背包优化) 显然会T得起飞. 接下来,我们可以换一种角度来思考这个问题. 首先,我们可以假设没有每个物品的数量的限制,那么这样就会变成一个很简单的完全背包问题. 至于完全背包怎么写,我们在这里就不做

bzoj 1042: [HAOI2008]硬币购物【容斥原理+dp】

当然是容斥啦. 用dp预处理出\( f[i] \),表示在\( i \)价格时不考虑限制的方案数,转移方程是\( f[i]+=f[i-c[j]] \),用状压枚举不满足的状态容斥一下即可. #include<iostream> #include<cstdio> using namespace std; const long long N=100005; long long c[10],T,d[10],s,f[N],ans; long long read() { long long

BZOJ 1042: [HAOI2008]硬币购物(容斥原理)

http://www.lydsy.com/JudgeOnline/problem.php?id=1042 题意: 思路: 如果不考虑硬币个数的话,这就是一道完全完全背包的题目. 直接求的话行不通,于是这里要用容斥原理来做. 简单来说,ans=一种没超-一种硬币超+两种硬币超-三种硬币超+四种硬币超. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio>

BZOJ 1042 [HAOI2008]硬币购物 容斥原理

题意:链接 方法:容斥原理 解析:简单题,不掉坑都对不起我自己 这题很好想的一个容斥原理,因为一共只有四种硬币,我们不方便计算满足题中要求的方案数,但是从反向思考,我们需要做的就是减掉奇数个硬币用超额的情况,然后加上偶数个硬币用超额的情况就是最终的答案(当然状态是0000的时候看做是一个基准). 然后我没什么说的了,只是有一些细节需要注意下: 1.要用long long 2.完全背包千万不要傻到每次重新背,直接一次预处理就好,不过我为什么要重新背啊!(差了8s) 代码: #include <cs

bzoj 1042 HAOI2008 硬币购物

这道题思路是在是神. 先dp出没有限制时候的方案数. dp的时候注意 先循环 1..4 再循环 1..maxs 防止重复.边界是f[0] = 1. 这么基础的背包都忘记了=_= 接下来处理有重复的问题,容斥原理     容斥原理说起来很简单,但有一些很神奇的应用,比如这道题. 最终的答案 = 没有限制的方案 - 其中一种超了限制的方案 + 其中两种超了限制的方案 - 三种超了限制的方案 + 四种超了限制的方案 ans = f[s] + f[s - c[i]*(d[i]+1)]  - ……  +

【BZOJ 1042】 [HAOI2008]硬币购物

1042: [HAOI2008]硬币购物 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1175  Solved: 697 [Submit][Status] Description 硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. Input 第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s Output