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) ...
随机推荐
- XShell命令行使用
1.建立连接: 2.查看总体目录: 3.查看对应服务目录: 4.删除对应jar包后,再查看目录下文件: 5.上传对应的jar文件: 6.重启服务 7.查看服务日志: 8.mv old-name new ...
- python git log
# -*- coding: utf-8 -*- # created by vince67 Feb.2014 # nuovince@gmail.com import re import os imp ...
- 【iOS开发-55】图片轮播案例:scrollView的分页、滚动栏、利用代理控制定时器和Page Control以及多线程问题
案例: (1)用storyboard布局,这里用了三样东西. --UIScrollView就是我们准备存放滚动图片的容器. --Page Control就是控制页数的那几个小点点.能够设置有多少个点. ...
- 码云的GIT操作
git操作 git initgit add .git commit -m ""git remote add origin https://git.coding.net/jessei ...
- zabbix分组报警
生产上需要在出现报警情况下,不同的主机发送报警给不同的用户 下面实例为分组为dev(开发组)和ops(运维组) 1.把主机进行分组 创建主机群组 配置-->主机群组-->创建主机群组,创建 ...
- 纯css 实现 三角形、梯形等 效果
今天一个刚开始学习html 的小白问我一个问题,css 可以实现正方形,长方形,和圆型(border-radius),怎么能做出个三角形.梯形等等形状呢?于是我便开启了装逼模式, 给他讲解了一下我的思 ...
- 【oracle11g,17】存储结构: 段的类型,数据块(行连接、行迁移,块头),段的管理方式,高水位线
一.段的类型: 1.什么是段:段是存储单元. 1.段的类型有: 表 分区表 簇表 索引 索引组织表(IOT表) 分区索引 暂时段 undo段 lob段(blob ,clob) 内嵌表(record类型 ...
- demo 微信毛玻璃效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- es6 webpack转es5
更新时间: 2018-7-31 首次更新. 先生成package.json npm init -y 再安装以下npm插件 npm i babel-core babel-loader babel-pre ...
- Centos6.6 以rpm方式安装mysql5.6
一.查看系统中有没有mysql的源 yum repolist all | grep mysql 二.配置源 1.配置源参考mysql官方给出的源配置,https://dev.mysql.com/doc ...