题面

传送门: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个....)

那么,我们就可以根据这个定理求出不可行的方案总数。

对于这题来说,代码如下:

  1. for(a[1]=0;a[1]<=1;a[1]++)
  2. for(a[2]=0;a[2]<=1;a[2]++)
  3. for(a[3]=0;a[3]<=1;a[3]++)
  4. for(a[4]=0;a[4]<=1;a[4]++)
  5. {
  6. int cnt=0,t_s=s;
  7. for(int j=1;j<=4;j++)
  8. if(a[j]==1) cnt++,t_s-=(d[j]+1)*c[j];
  9. if(cnt%2==0) cnt=1;
  10. else cnt=-1;
  11.  
  12. if(t_s>=0)
  13. ans=ans+cnt*f[t_s];
  14. }

这样写绝对不推荐,因为这样写很丑。

那么,这题就可以AC啦


Code

  1. //Luogu P1450 [HAOI2008]硬币购物
  2. //Aug,27th,2018
  3. //DP+容斥
  4. #include <iostream>
  5. #include <cstdio>
  6. using namespace std;
  7. long long read()
  8. {
  9. long long x=0,f=1; char c=getchar();
  10. while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
  11. while(isdigit(c)){x=x*10+c-'0';c=getchar();}
  12. return x*f;
  13. }
  14. const int N=100000+1000;
  15. long long f[N];
  16. int n,m;
  17. long long c[5],d[5];
  18. int main(int argc, char **argv)
  19. {
  20. for(int i=1;i<=4;i++)
  21. c[i]=read();
  22. m=read();
  23.  
  24. f[0]=1;
  25. for(int j=1;j<=4;j++)
  26. for(int i=c[j];i<=100000;i++)
  27. f[i]+=f[i-c[j]];
  28. for(int i=1;i<=m;i++)
  29. {
  30. for(int j=1;j<=4;j++)
  31. d[j]=read();
  32. int s=read(),a[5];
  33. long long ans=0;
  34. for(a[1]=0;a[1]<=1;a[1]++)
  35. for(a[2]=0;a[2]<=1;a[2]++)
  36. for(a[3]=0;a[3]<=1;a[3]++)
  37. for(a[4]=0;a[4]<=1;a[4]++)
  38. {
  39. int cnt=0,t_s=s;
  40. for(int j=1;j<=4;j++)
  41. if(a[j]==1) cnt++,t_s-=(d[j]+1)*c[j];
  42. if(cnt%2==0) cnt=1;
  43. else cnt=-1;
  44.  
  45. if(t_s>=0)
  46. ans=ans+cnt*f[t_s];
  47. }
  48.  
  49. printf("%lld\n",ans);
  50. }
  51. return 0;
  52. }

正解(c++)

[Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥的更多相关文章

  1. Luogu P1450 [HAOI2008]硬币购物 背包+容斥原理

    考虑如果没有个数的限制,那么就是一个完全背包,所以先跑一个完全背包,求出没有个数限制的方案数即可. 因为有个数的限制,所以容斥一下:没有1个超过限制的方案=至少0个超过限制-至少1个超过限制+至少2个 ...

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

    题目链接:BZOJ - 1042 题目分析 首先 Orz Hzwer ,代码题解都是看的他的 blog. 这道题首先使用DP预处理,先求出,在不考虑每种硬币个数的限制的情况下,每个钱数有多少种拼凑方案 ...

  3. bzoj1042: [HAOI2008]硬币购物(DP+容斥)

    1600+人过的题排#32还不错嘿嘿 浴谷夏令营讲过的题,居然1A了 预处理出f[i]表示购买价值为i的东西的方案数 然后每次询问进行一次容斥,答案为总方案数-第一种硬币超限方案-第二种超限方案-第三 ...

  4. BZOJ 1042: [HAOI2008]硬币购物( 背包dp + 容斥原理 )

    先按完全背包做一次dp, dp(x)表示x元的东西有多少种方案, 然后再容斥一下. ---------------------------------------------------------- ...

  5. 洛谷P1450 [HAOI2008]硬币购物 背包+容斥

    无限背包+容斥? 观察数据范围,可重背包无法通过,假设没有数量限制,利用用无限背包 进行预处理,因为实际硬币数有限,考虑减掉多加的部分 如何减?利用容斥原理,减掉不符合第一枚硬币数的,第二枚,依次类推 ...

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

    题解: 计数题 首先考虑容斥 这题很明显加了限制状态就很多 考虑没有限制 显然可以直接dp 然后 我们看一下 容斥 某一个使用>=k张 那么其实就是 f[i-k*c[]] 于是这样就可以做了

  7. Luogu P1450 [HAOI2008]硬币购物

    题目 一个很自然的想法是容斥. 假如只有一种硬币,那么答案就是没有限制的情况下买\(s\)的方案数减去强制用了\(d+1\)枚情况下买\(s\)的方案数即没有限制的情况下买\(s-c(d+1)\)的方 ...

  8. P1450 [HAOI2008]硬币购物(完全背包+容斥)

    P1450 [HAOI2008]硬币购物 暴力做法:每次询问跑一遍多重背包. 考虑正解 其实每次跑多重背包都有一部分是被重复算的,浪费了大量时间 考虑先做一遍完全背包 算出$f[i]$表示买价值$i$ ...

  9. 2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP)

    2021.12.06 P1450 [HAOI2008]硬币购物(组合数学+抽屉原理+DP) https://www.luogu.com.cn/problem/P1450 题意: 共有 44 种硬币.面 ...

随机推荐

  1. UltraEdit文字编辑器菜单热键推荐

    键盘映射和自定义菜单热键 任何使用过UltraEdit / UEStudio一段时间的人都可能会告诉您,他们如此喜欢它的原因之一是"几乎所有东西都是可定制的".看一下产品鉴定,您会 ...

  2. jQuery中使用$.each()遍历数组时要注意的地方

    使用jQuery中 $.each()遍历数组,要遍历的数组不能为空(arry!="") 例如:           $.each(arry, function (i, item)  ...

  3. matlab一个figure画多个子图,和多个figure画多个图。

    参考:https://blog.csdn.net/xiaotao_1/article/details/79024488 1,一个figure画多个子图: figure(10) % define fig ...

  4. 题解【QTree3】

    题目描述 给出N个点的一棵树(N-1条边),节点有白有黑,初始全为白 有两种操作: 0 i : 改变某点的颜色(原来是黑的变白,原来是白的变黑) 1 v : 询问1到v的路径上的第一个黑点,若无,输出 ...

  5. CentOS7 系统安全的设置

    一.禁止root远程直接登录 # 创建普通用户,并设置密码 useradd bluceli #新建账户 passwd bluceli #设置密码 # 不允许root远程直接登录 vim /etc/ss ...

  6. linux 已放弃(吐核) (core dumped) 问题分析

    在运行自己写的 C 多线程程序是,出现:已放弃(吐核)  问题. 出现这种问题一般是下面这几种情况: 1.内存越界 2.使用的非线程安全的函数 3.全局数据未加锁保护 4.非法指针 5.堆栈溢出 也就 ...

  7. Elasticsearch(4):映射

      ES中的映射(mapping)是用于定义索引中文档以及文档中的字段如何被存储和索引(动词)的一种机制,例如,通过映射我们可以进行如下的这些定义: 索引文档中,哪些字符型字段应该被当做全文本类型: ...

  8. MeteoInfoLab脚本示例:Streamline流线图

    绘制Stramline流线图的函数是streamline,需要两个变量(U/V分量或者风向/风速).脚本程序: f = addfile('D:/Temp/GrADS/model.ctl') u = f ...

  9. Monolog - Logging for PHP

    github地址:https://github.com/Seldaek/monolog 使用 Monolog 安装 核心概念 日志级别 配置一个日志服务 为记录添加额外的数据 使用通道 自定义日志格式 ...

  10. linux(centos8):安装java jdk 15 (java 15)

    一,下载jdk15 官方网站: https://www.oracle.com/java/ 下载页面: https://www.oracle.com/cn/java/technologies/javas ...