[Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
题面
传送门:https://www.luogu.org/problemnew/show/P1450
Solution
这是一道很有意思的在背包里面做容斥的题目。
首先,我们可以很轻松地想到暴力做背包的做法。
就是对于每一次询问,我们都做一次背包。
复杂度O(tot*s*log(di)) (使用二进制背包优化)
显然会T得起飞。
接下来,我们可以换一种角度来思考这个问题。
首先,我们可以假设没有每个物品的数量的限制,那么这样就会变成一个很简单的完全背包问题。
至于完全背包怎么写,我们在这里就不做过多讨论,如有需要,看看代码就能理解了。
完全背包做完后,我们可以得到一个f[i]表示填满i的背包的方案数的数组。
那么,我们接下来可以用容斥来解决不可行的方案的问题。
假设只有1件物品的使用次数超出了所给的数量,假设这件物品是第x件。
那么可以用 f[s-(d[x]+1)*c[x]] 表示这件物品不可行的方案总数。
因为对于花钱数为 s-(d[x]+1)*c[x] 里面的每一种方法,都可以通过使用购买 d[x]+1件的x物品来超出所给的数量。所以 f[s-(d[x]+1)*c[x]] 可以表示该物品不可行方案总数。
那么答案是四件物品不可行方案总数这和吗?
nope
因为我们会重复减去一些东西。例如:一种方案即超出了第一件物品的使用数,也超出了第二件物品的使用数,我们却重复扣除了这种方案两次。
所以说我们这时候就得使用容斥来解决这个问题。
容斥中有一个很基础的定理(我不会证):
对于有n的限制条件的事件,只要其中符合一个条件就算可行,其可行方案总数为:
(符合其中0个(条件的方案数,后同)-符合其中1个+符合其中2个-符合其中3个+符合其中4个-符合其中5个+符合其中6个....)
那么,我们就可以根据这个定理求出不可行的方案总数。
对于这题来说,代码如下:
for(a[1]=0;a[1]<=1;a[1]++)
for(a[2]=0;a[2]<=1;a[2]++)
for(a[3]=0;a[3]<=1;a[3]++)
for(a[4]=0;a[4]<=1;a[4]++)
{
int cnt=0,t_s=s;
for(int j=1;j<=4;j++)
if(a[j]==1) cnt++,t_s-=(d[j]+1)*c[j];
if(cnt%2==0) cnt=1;
else cnt=-1; if(t_s>=0)
ans=ans+cnt*f[t_s];
}
这样写绝对不推荐,因为这样写很丑。
那么,这题就可以AC啦
Code
//Luogu P1450 [HAOI2008]硬币购物
//Aug,27th,2018
//DP+容斥
#include <iostream>
#include <cstdio>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int N=100000+1000;
long long f[N];
int n,m;
long long c[5],d[5];
int main(int argc, char **argv)
{
for(int i=1;i<=4;i++)
c[i]=read();
m=read(); f[0]=1;
for(int j=1;j<=4;j++)
for(int i=c[j];i<=100000;i++)
f[i]+=f[i-c[j]];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=4;j++)
d[j]=read();
int s=read(),a[5];
long long ans=0;
for(a[1]=0;a[1]<=1;a[1]++)
for(a[2]=0;a[2]<=1;a[2]++)
for(a[3]=0;a[3]<=1;a[3]++)
for(a[4]=0;a[4]<=1;a[4]++)
{
int cnt=0,t_s=s;
for(int j=1;j<=4;j++)
if(a[j]==1) cnt++,t_s-=(d[j]+1)*c[j];
if(cnt%2==0) cnt=1;
else cnt=-1; if(t_s>=0)
ans=ans+cnt*f[t_s];
} printf("%lld\n",ans);
}
return 0;
}
正解(c++)
[Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥的更多相关文章
- Luogu P1450 [HAOI2008]硬币购物 背包+容斥原理
考虑如果没有个数的限制,那么就是一个完全背包,所以先跑一个完全背包,求出没有个数限制的方案数即可. 因为有个数的限制,所以容斥一下:没有1个超过限制的方案=至少0个超过限制-至少1个超过限制+至少2个 ...
- [BZOJ 1042] [HAOI2008] 硬币购物 【DP + 容斥】
题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案 ...
- bzoj1042: [HAOI2008]硬币购物(DP+容斥)
1600+人过的题排#32还不错嘿嘿 浴谷夏令营讲过的题,居然1A了 预处理出f[i]表示购买价值为i的东西的方案数 然后每次询问进行一次容斥,答案为总方案数-第一种硬币超限方案-第二种超限方案-第三 ...
- BZOJ 1042: [HAOI2008]硬币购物( 背包dp + 容斥原理 )
先按完全背包做一次dp, dp(x)表示x元的东西有多少种方案, 然后再容斥一下. ---------------------------------------------------------- ...
- 洛谷P1450 [HAOI2008]硬币购物 背包+容斥
无限背包+容斥? 观察数据范围,可重背包无法通过,假设没有数量限制,利用用无限背包 进行预处理,因为实际硬币数有限,考虑减掉多加的部分 如何减?利用容斥原理,减掉不符合第一枚硬币数的,第二枚,依次类推 ...
- 【bzoj1042】[HAOI2008]硬币购物 背包dp+容斥原理
题解: 计数题 首先考虑容斥 这题很明显加了限制状态就很多 考虑没有限制 显然可以直接dp 然后 我们看一下 容斥 某一个使用>=k张 那么其实就是 f[i-k*c[]] 于是这样就可以做了
- Luogu P1450 [HAOI2008]硬币购物
题目 一个很自然的想法是容斥. 假如只有一种硬币,那么答案就是没有限制的情况下买\(s\)的方案数减去强制用了\(d+1\)枚情况下买\(s\)的方案数即没有限制的情况下买\(s-c(d+1)\)的方 ...
- P1450 [HAOI2008]硬币购物(完全背包+容斥)
P1450 [HAOI2008]硬币购物 暴力做法:每次询问跑一遍多重背包. 考虑正解 其实每次跑多重背包都有一部分是被重复算的,浪费了大量时间 考虑先做一遍完全背包 算出$f[i]$表示买价值$i$ ...
- 2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP)
2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP) https://www.luogu.com.cn/problem/P1450 题意: 共有 44 种硬币.面 ...
随机推荐
- Appium的一些问题的总结答案
问题 1. error: Failed to start an Appium session, err was: Error: Requested a new session but one ...
- pycharm 配置 github
今天突然想把自己的代码上传到github上去,然后就研究了下pycharm的配置. 首先呢,你得有个github的账号,然后建立一个项目. 然后打开pycharm,选择file->Setting ...
- spring-boot-route(四)全局异常处理
在开发中,我们经常会使用try/catch块来捕获异常进行处理,如果有些代码中忘记捕获异常或者不可见的一些异常出现,就会响应给前端一些不友好的提示,这时候我们可以使用全局异常处理.这样就不用在代码中写 ...
- 047 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 09 嵌套while循环应用
047 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 09 嵌套while循环应用 本文知识点:嵌套while循环应用 什么是循环嵌套? 什么是循环嵌套? ...
- 026 01 Android 零基础入门 01 Java基础语法 03 Java运算符 06 if-else条件结构
026 01 Android 零基础入门 01 Java基础语法 03 Java运算符 06 if-else条件结构 本文知识点:Java中的if-else条件结构语句 上文回顾--if条件结构 如果 ...
- 如何选择JVM垃圾回收器?
明确垃圾回收器组合 -XX:+UseSerialGC 年轻代和老年代都用串行收集器 -XX:+UseParNewGC 年轻代使用ParNew,老年代使用 Serial Old -XX:+UsePara ...
- Python装饰器实现带参数和不带参数
1 def log(text=None): 2 3 if isinstance(text, str): 4 def decorator(func): 5 @functools.wraps(func) ...
- shell-逻辑操作符讲解与文件条件测试多范例多生产案例
1. 逻辑操作符 在书写测试表达式时,可以使用表1.1中的逻辑操作符实现复杂的条件测试 表1.1逻辑连接符 提示: ! 中文意思是反:与一个逻辑值相反的逻辑值 -a 中文意思是与(and & ...
- linux 虚拟机下 安装redis
虚拟机安装linux,打开,挂起就好: 使用ssh连接,这里使用的是Moba Xterm 可以ssh 可以ftp 满足你的日常开发所需,开发必备.每个人都有自己顺手的工具,你喜欢就好 虚拟机挂一边就 ...
- 2016年 实验五 Internet与网络工具的使用
实验五 Internet与网络工具的使用 [实验目的] 本实验目的在于掌握 Telnet.FTP.Email的工作机理,并会在 Internet 上熟练使用相关工具软件. [实验条件] ⑴.个人计算机 ...