DP(正解完全背包+容斥)
DP
Time Limit:10000MS Memory Limit:165888KB 64bit IO Format:%lld & %llu
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 //背包问题,容斥原理
//不得不说这是个好题,背包问题应该都会,主要是这个容斥原理,要理解,举个例子说明下日常中经常遇到的这个定理 一次考试,某班有15人数学得满分,有12人语文得满分,并且有4人语、数都是满分,那么这个班至少有一门得满分的同学有多少人?
答案:15+12-4=23 思路是,首先不限制4种钱币的个数,看组成某个价格的方案数共有多少
然后借助容斥定理减去4种钱币超过个数限制的情况,就不多不少的求出答案
dp[i]表示了|不限制| 硬币数目的最多付款方法,怎么转移应该都会
那么只需将
dp[res]
-d1超过的限制数 - d2超过的... - d3... - d4...
+ (d1与d2) + ... + (d3与d4)
- (d1,d2,d3)
+ (d1+d2+d3+d4)
就行了
如果还不理解再继续看
这题的运用容斥定理,看了篇博客,例子写的很好,不然我真不太好理解,尤其是 d[i]++ 是为什么
我们来理解 x = dp[s]-dp[s-(d1+1)*c1] 的含义:
x 表示 c1 硬币的数量不超过 d1 个而其他三种硬币的数量不限制拼成 s 的方案数。
我们举着例子来说明,假设现在有两种硬币,面值分别为1和2,
那么我们求出 dp: dp[0]=1 , dp[1]=1 , dp[2]=2 , dp[3]=2 , dp[4]=3 , dp[5]=3 , dp[6]=4 。
其中dp[3]的两种分别为 3 = 1+1+1 = 1+2 ,dp[6]的四种为: 6 = 1+1+1+1+1+1 = 1+1+1+1+2 = 1+1+2+2 = 2+2+2
假如我们现在求第一种硬币最多使用两个,第二种硬币无限制的方案数,按照我们说的 x = dp[6]-dp[6--(2+1)*1]=dp[6]-dp[3]=2。
也就是 6 = 1+1+2+2 = 2+2+2 两种。发现删除了 1+1+1+1+1+1 和 1+1+1+1+2 两种情况,
为什么能够通过减去 dp[3] 删掉这两种?我们来看 dp[3], 3 = 1+1+1 = 1+2 ,
d1+1 就是相当于用掉了 di 个硬币,所以 dp[3] 的情况要从答案中剔除
先来易懂的用for容斥的代码
#include <iostream>
#include <stdio.h>
using namespace std; typedef long long LL;
#define MAX 100005 LL c[],d[];
LL dp[MAX];
LL ans; int main()
{
for (int i=;i<=;i++)
scanf("%lld",&c[i]);
int tot;
scanf("%lld",&tot);
dp[]=;
for (int i=;i<=;i++)
for (int j=c[i];j<=;j++)
dp[j]+=dp[j-c[i]];
while (tot--)
{
LL res;
for (int i=;i<=;i++)
{
scanf("%lld",&d[i]);
d[i]++;
} scanf("%lld",&res);
ans=dp[res]; int i,j,k;
for (i=;i<=;i++)
if (res>=c[i]*d[i])
ans-=dp[res-c[i]*d[i]]; for (i=;i<=;i++)
for (j=i+;j<=;j++)
if (res>=c[i]*d[i]+c[j]*d[j])
ans+=dp[res-c[i]*d[i]-c[j]*d[j]];
for (i=;i<=;i++)
for (j=i+;j<=;j++)
for (k=j+;k<=;k++)
if (res>=c[i]*d[i]+c[j]*d[j]+c[k]*d[k])
ans-=dp[res-c[i]*d[i]-c[j]*d[j]-c[k]*d[k]];
if (res>=c[]*d[]+c[]*d[]+c[]*d[]+c[]*d[])
ans+=dp[res-c[]*d[]-c[]*d[]-c[]*d[]-c[]*d[]]; printf("%lld\n",ans); }
return ;
}
这个是DFS去处理容斥,简洁明了,时间是一样的
#include <iostream>
#include <stdio.h>
using namespace std; typedef long long LL;
#define MAX 100005 LL c[],d[];
LL dp[MAX];
LL ans; void dfs(int x,int k,LL s)
{
if (s<)return;
if (x==)
{
if (k%)ans-=dp[s];
else ans+=dp[s];
return;
}
dfs(x+,k+,s-(d[x]+)*c[x]);
dfs(x+,k,s);
}
int main()
{
for (int i=;i<=;i++)
scanf("%lld",&c[i]);
int tot;
scanf("%lld",&tot);
dp[]=;
for (int i=;i<=;i++)
for (int j=c[i];j<=;j++)
dp[j]+=dp[j-c[i]]; while (tot--)
{
LL res;
for (int i=;i<=;i++)
scanf("%lld",&d[i]); scanf("%lld",&res);
ans= ;
dfs(,,res);
printf("%lld\n",ans);
}
return ;
}
DP(正解完全背包+容斥)的更多相关文章
- Luogu-P1450 [HAOI2008]硬币购物-完全背包+容斥定理
Luogu-P1450 [HAOI2008]硬币购物-完全背包+容斥定理 [Problem Description] 略 [Solution] 上述题目等价于:有\(4\)种物品,每种物品有\(d_i ...
- 洛谷P1450 [HAOI2008]硬币购物 背包+容斥
无限背包+容斥? 观察数据范围,可重背包无法通过,假设没有数量限制,利用用无限背包 进行预处理,因为实际硬币数有限,考虑减掉多加的部分 如何减?利用容斥原理,减掉不符合第一枚硬币数的,第二枚,依次类推 ...
- P1450 [HAOI2008]硬币购物(完全背包+容斥)
P1450 [HAOI2008]硬币购物 暴力做法:每次询问跑一遍多重背包. 考虑正解 其实每次跑多重背包都有一部分是被重复算的,浪费了大量时间 考虑先做一遍完全背包 算出$f[i]$表示买价值$i$ ...
- BZOJ-1042:硬币购物(背包+容斥)
题意:硬币购物一共有4种硬币.面值分别为c1,c2,c3,c4.某人去商店买东西,去了tot次.每次带di枚ci硬币,买si的价值的东西.请问每次有多少种付款方法. 思路:这么老的题,居然今天才做到. ...
- BZOJ 1042 [HAOI2008]硬币购物(完全背包+容斥)
题意: 4种硬币买价值为V的商品,每种硬币有numi个,问有多少种买法 1000次询问,numi<1e5 思路: 完全背包计算出没有numi限制下的买法, 然后答案为dp[V]-(s1+s2+s ...
- P4707-重返现世【dp,数学期望,扩展min-max容斥】
正题 题目链接:https://www.luogu.com.cn/problem/P4707 题目大意 \(n\)个物品,每次生成一种物品,第\(i\)个被生成的概率是\(\frac{p_i}{m}\ ...
- BZOJ1042 [HAOI2008]硬币购物 【完全背包 + 容斥】
1042: [HAOI2008]硬币购物 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 2924 Solved: 1802 [Submit][St ...
- [LOJ#3119][Luogu5405][CTS2019]氪金手游(DP+容斥)
先考虑外向树的做法,显然一个点在其子树内第一个出现的概率等于它的权值除以它子树的权值和.于是f[i][j]表示i的子树的权值和为j时,i子树内所有数的相互顺序都满足条件的概率,转移直接做一个背包卷积即 ...
- 知识点简单总结——minmax容斥
知识点简单总结--minmax容斥 minmax容斥 好像也有个叫法叫最值反演? 就是这样的一个柿子: \[max(S) = \sum\limits_{ T \subseteq S } min(T) ...
随机推荐
- 前端存储之Web Sql Database
前言 在上一篇前端存储之indexedDB中说到,我们项目组要搞一个前后端分离的项目,要求在前端实现存储,我们首先找到了indexedDB,而我们研究了一段时间的indexedDB后,发现它并不是很适 ...
- 服务器和java程序的桥梁--jdbc/hibernate
现实的应用程序都是用户通过可视化界面发出指令从而修改数据库.本篇文章以Oracle为例,模拟怎么通过java代码实现数据库的增删改查. 新建一个Java项目,要建好桥梁,首先要拷入驱动Jar包放在项目 ...
- Win7安装了Visual Studio 2008没有快捷方式怎么办
在C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE,就是这个devenv.exe了
- mysql常用命令和函数
一.DROP IF EXISTS DROP FUNCTION IF EXISTS fun;DROP TABLE IF EXISTS table; 二.数据表1.建立表CREATE TABLE test ...
- Linux非阻塞IO(二)网络编程中非阻塞IO与IO复用模型结合
上文描述了最简易的非阻塞IO,采用的是轮询的方式,这节我们使用IO复用模型. 阻塞IO 过去我们使用IO复用与阻塞IO结合的时候,IO复用模型起到的作用是并发监听多个fd. 以简单的回射服务器 ...
- 最小化JavaScript代码
1.去除不必要的格式符.空白符.凝视符. 这个操作.事实上能够理解为是一种格式化.尽管它操作的结果事实上是去除掉原始文件的那些格式. 2.模糊(Obfuscation)处理JAVASCRIP脚本源码. ...
- DNS 取得授权
1.阿里云上cnroot.cn申请DNS解析服务器 也就是cnroot.cn下的子域名都从这个DNS上获取. 如www.cnroot.cn 如 handle.cnroot.cn 2.vi /home/ ...
- vue vue-router beforeRouteEnter
beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实 ...
- js:获得时间
<script type="text/javascript"> function bodyLoad() { var dateTime = new Date(); var ...
- Eclipse中设置格式化jsp自动换行
JSP代码换行:Window->Preferences->Web->JSP Files->Editor->Line width