Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)
题意:
给出 n 种纸币的面值以及数量,求最少使用多少张纸币能凑成 M 的面额。
细节:
好像是要输出方案,看来很是头疼啊。
分析:
多重背包,裸体???
咳咳,好吧需要低调,状态就出来了: dp [ i ] 表示面额为 i 最少需要多少张纸币组成。
转移:dp [ i ] = min ( dp [ i ] , dp [ i - w [ j ] × k ] + k ) ( k 表示当前纸币有几张,0 ≤ k ≤ num [ j ] 表示这类纸币的数量)
好了你就完成了此题的部分分,本人蒟蒻打死都想不到背包还能优化可是它显然可以。
所以开始向满分冲刺,对于上方的转移你显然不能优化,对于一个转移竟然跟三个变量有关,嘿嘿嘿,这个转移很有心机,
我们需要进行方程的转换,不妨先来看一下是否存在重复,假设当前 num [ j ] = 2,w [ j ] = 1 时:
i = 3 时,可以从 3、2、1 进行转移
i = 4 时,可以从 4、3、2 进行转移
i = 5 时,可以从 5、4、3 进行转移
顿时豁然开朗,存在重复存在优化的可能性,但是却对应了不同的价值,比如 i = 3 时从 2 进行转移的花费为 1 ,但是对于 i = 4 来说花费就变成了 2 ,所以对于当前的第 j 层来说其转移的值是不定的,所以无法进行优化。
但如果先在转移之前每个值都减去 i 的话,就会出现这样的情况:
i = 3 时,从 dp [ 1 ] - 1 + 3,dp [ 2 ] - 2 + 3,dp [ 3 ] - 3 + 3 转移
i = 4 时,从 dp [ 2 ] - 2 + 4,dp [ 3 ] - 3 + 4,dp [ 4 ] - 4 + 4 转移
不然发现对于 i 来说其都加了 i ,但前方的转移都是相同的,这样就可以开始进一步的优化了。
不妨令 d = v [ i ],a = j / d,b = j % d ,即 j = a × d + b。
这样方程就变化成了:dp [ j ] = min ( dp [ b + k × d] - k )+ a
所以只需要维护一个关于 dp [ b + k × d ] - k 单调递增的队列即可。
最后我们再来考虑一下如何打印出最后的方案,其实只需要记录每个转移是从哪一个面额而来的以及它当前用了哪一种面额的纸币即可,且这只是其中的一种方案。
代码:
#include<bits/stdc++.h>
#define MAXN 20005
using namespace std;
struct Node{
int ans,W;
}que[MAXN];
int n, m, w[MAXN], num[MAXN], f[MAXN], d[205][MAXN];
void print(int x, int y){ //打印方案
if (!x) return;
print(x-1, d[x][y]);
printf("%d ", (y-d[x][y])/w[x]);
}
int main(){
scanf("%d", &n);
for (int i=1; i<=n; i++) scanf("%d", &w[i]);
for (int i=1; i<=n; i++) scanf("%d", &num[i]);
scanf("%d", &m);
memset(f, 0x3f3f3f, sizeof f);
f[0]=0;
for (int i=1; i<=n; i++){
for (int j=0; j<w[i]; j++){
int head=1, tail=0;
for (int k=j, cnt=0; k<=m; cnt++, k+=w[i]){
if (tail-head==num[i]) head++; //维护队首
int Ans=f[k]-cnt;
while (head<=tail && Ans<que[tail].ans) --tail; //维护队尾
que[++tail].ans=Ans, que[tail].W=k; //加入新的元素
f[k]=que[head].ans+cnt; //转移当前的最有状态
d[i][k]=que[head].W; //记录当前的最有转移从何而来
}
}
}
printf("%d\n", f[m]);
print(n, m); //打印方案
return 0;
}
小结:
可以把该类问题进行一般化的处理,也就是将方程转化为 dp [ i ] = min ( dp [ i ] , dp [ i - w [ j ] × k ] + k × v [ i ] ) 同理它可以转化为以下的式子:
假设 d = v [ i ],a = j / d,b = j % d,即 j = a × d + b
dp [ i ][ j ] = max { dp [ i - 1 ] [ b + k × d ] - k × w[i] } + a × w[i] (a – m[i] <= k <= a)
考虑用单调队列优化即可。Q A Q
Luogu 3423 [POI 2005]BAN-银行票据 (多重背包单调队列优化 + 方案打印)的更多相关文章
- [BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化)
[BZOJ4182]Shopping (点分治+树上多重背包+单调队列优化) 题面 马上就是小苗的生日了,为了给小苗准备礼物,小葱兴冲冲地来到了商店街.商店街有n个商店,并且它们之间的道路构成了一颗树 ...
- 【POJ1276】Cash Machine(多重背包单调队列优化)
大神博客转载http://www.cppblog.com/MatoNo1/archive/2011/07/05/150231.aspx多重背包的单调队列初中就知道了但一直没(不会)写二进制优化初中就写 ...
- hdu 2844 多重背包+单调队列优化
思路:把价值看做体积,而价值的大小还是其本身,那么只需判断1-m中的每个状态最大是否为自己,是就+1: #include<iostream> #include<algorithm&g ...
- poj1742 Coins(多重背包+单调队列优化)
/* 这题卡常数.... 二进制优化或者单调队列会被卡 必须+上个特判才能过QAQ 单调队列维护之前的钱数有几个能拼出来的 循环的时候以钱数为步长 如果队列超过c[i]就说明队头的不能再用了 拿出来 ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
- bzoj 1531 Bank notes 多重背包/单调队列
多重背包二进制优化终于写了一次,注意j的边界条件啊,疯狂RE(还是自己太菜了啊啊)最辣的辣鸡 #include<bits/stdc++.h> using namespace std; in ...
- POJ 1742 Coins(多重背包, 单调队列)
Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...
- 多重背包 /// 单调队列DP oj1943
题目大意: em.... 就是多重背包 挑战340页的东西 ...自己的笔记总结总是比较乱的 重点:原始的状态转移方程中 更新第 i 种物品时 重量%w[i] 的值不同 则它们之间是相互独立的: 1- ...
- Luogu 2569 [SCOI2010]股票交易 (朴素动规转移 + 单调队列优化)
题意: 已知未来 N 天的股票走势,第 i 天最多买进 as [ i ] 股每股 ap [ i ] 元,最多卖出 bs [ i ] 股每股 bp [ i ] 元,且每天最多拥有 Mp 股,且每两次交易 ...
随机推荐
- E.华华给月月准备礼物
链接:https://ac.nowcoder.com/acm/contest/392/E 题意: 二月中旬虐狗节前夕,华华决定给月月准备一份礼物.为了搭建礼物的底座,华华需要若干根同样长的木棍.华华手 ...
- bzoj3583 杰杰的女性朋友 || bzoj4362 Graph
http://210.33.19.103/problem/2174 很显然是矩阵快速幂的题,设有in和ou矩阵,设in矩阵的转置为in' 显然可以直接暴力求出任意两点间走一步路径条数,然后求其d次幂, ...
- siege官方文档(译)(二)
WHY DO I NEED IT? Siege was written for both web developers and web systems administrators. siege是为了 ...
- Excel 通过pl/sql导入到数据库 文本导入器 odbc导入器
Excel 通过pl/sql导入到数据库 第一种方法:文本导入器 1.准备Excel导入数据 jc.xls 2.把 jc.xls 文件 改为 jc.csv文件 3.在数据库里建一张jc表(FLH ...
- Java的Cloneable接口还有深浅复制
我的小记录 首先语法上,搞清除,Java有个Cloneable接口,但这个接口是没有定义方法的. 那实现了这个接口有什么用呢? 再看Object类中,有个clone()方法,这个方法提供一个浅复制的功 ...
- vue项目打包后文本溢出代码消失问题
补充 https://www.cnblogs.com/richard1015/p/8526988.html vue webpack 打包编译-webkit-box-orient: vertical 后 ...
- 使用em和rem替代px
rem是指根元素的字体大小,默认情况下html的字体大小为:16px=1rem.而em是相对单位,是基于它的祖先元素计算的. 如果我们不指定html和body的字体大小,要得到12px的rem需要这样 ...
- [已读]CSS禅意花园
蛮早的一本书,提到了一些小tip,比如负margin实现居中.FIR图像替换.
- postman中添加cookie信息
日常测试中有部分接口请求需要有登录信息,否则调用报错,那如何在postman中添加用户的cookie呢,主要分2个步骤: 第一步: Charles抓包获取Headers信息,拷贝Headers中的Co ...
- 【extjs6学习笔记】0.0 准备
1.下载ExtJS 6 下面是Ext JS 6正式版的GPL版本下载地址 https://www.sencha.com/legal/gpl/ 2.下载sencha cmd 安装完成后,命令行运行出现以 ...