博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1450 [HAOI2008]硬币购物
阅读量:5140 次
发布时间:2019-06-13

本文共 1463 字,大约阅读时间需要 4 分钟。

每种硬币有数量限制,感觉很不好算

先考虑一下如果没用限制时可以怎么做

显然直接背包一下就可以了

设 $f[i][j]$ 表示前 $i$ 种硬币选了一些,总价值为 $j$ 的方案数,转移显然,并且可以滚动数组优化

但是现在有限制,考虑容斥,设 $f[j]$ 表示不考虑限制总价值为 $j$ 的方案

一开始答案为 $f[S]$,然后发现多算了,可能硬币不够的方案也算进去了,所有考虑把每一种硬币多出的情况减去,就是强制一种硬币超过限制,其他的顺便选,这个值可以用 $f$ 求出

然后发现减多了,把两种硬币多出的情况减了 $C^{1}_{2}$ 次 ,把三种硬币多出的情况减了 $C^{1}_{3}$ 次,把四种硬币多出的情况减了 $C^{1}_{4}$ 次

所以要再把所有两种硬币多出的情况加上来,那么每两种的情况加了 $C^{2}_{2}$ 次,然后每两种硬币多出的情况就刚好只被减了一次

但是还有点问题,我们又多加了每三种硬币的情况,加了 $C^{2}_{3}$ 次,那么现在三种硬币的情况就没被扣掉

并且发现四种硬币的情况也被多加了,加了 $C^{2}_{4}$ 次,此时四种硬币超过限制的情况反而多加了 $2$ 次

先考虑把三种硬币多出的情况扣掉,把每三种硬币的情况减去,

那么此时每三种硬币的情况刚好被减了 $1$ 次,但是每四种硬币超过限制的情况又被扣了 $C^{3}_{4}$ 次

此时四种硬币的情况总共被扣了 $2$ 次

那么最后再把四种硬币的情况加上一次就好了

总结一下,没有限制 - 一个硬币的限制 + 两个硬币的限制 - 三个硬币的限制 + 四个硬币的限制

这就是最基础的容斥了,用位运算很方便实现

具体看代码吧

#include
#include
#include
#include
#include
using namespace std;typedef long long ll;inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f;}const int N=1e5+7;int c[7],d[7],n,m;ll f[N],ans;int main(){ for(int i=1;i<=4;i++) c[i]=read(); n=read(); f[0]=1; for(int i=1;i<=4;i++) for(int j=c[i];j
>j)&1) cnt++,t+=c[j+1]*(d[j+1]+1); if(t<=m) cnt&1 ? ans-=f[m-t] : ans+=f[m-t];//容斥 } printf("%lld\n",ans); } return 0;}

 

转载于:https://www.cnblogs.com/LLTYYC/p/10773808.html

你可能感兴趣的文章
62. Unique Paths
查看>>
Linux Linux程序练习十七
查看>>
数据库关系运算
查看>>
JavaSE基础之 IO流
查看>>
DDoS攻防战 (一) : 概述
查看>>
根据现有PDF模板填充信息(SpringBoot)
查看>>
div+css布局的好处
查看>>
《需求工程——软件建模与分析》阅读笔记一
查看>>
如何成为一枚好测试员
查看>>
【Nowcoder】玩游戏
查看>>
过滤器(Filter)
查看>>
字符串的操作
查看>>
性能优化之Java(Android)代码优化
查看>>
springMVC相关—文件上传
查看>>
由Oracle 11g SYSAUX 和 SYSTEM 表空间回收引发的联想
查看>>
uva 1416 Warfare And Logistics
查看>>
欲则不达
查看>>
盒子游戏
查看>>
OpenJudgeP1.10.08:病人排队__(刷题)_水题
查看>>
观察者模式
查看>>