【[USACO13NOV]没有找零No Change】
其实我是点单调队列的标签进来的,之后看着题就懵逼了
于是就去题解里一翻,发现楼上楼下的题解说的都好有道理,
f[j]表示一个再使用一个硬币就能到达i的某个之前状态,b[now]表示使用那个能使状态j变到i的硬币的面值,find表示这些花费可以到达的最大距离,由于前缀和保持单调可以用二分求解,方程不就是f[i]=max(f[i],find(p[f[j]]+b[now]))吗
但这道题怎么用单调队列优化呢
我们观察这个方程你会发现无论是b[now],p[f[j]]都跟i没有什么关系,而只要是p[f[j]]+b[now]越大,相应的find的值也就越大
于是我们就可以愉快的单调队列优化这个dp了,用一个单调队列把每次的p[f[j]]+b[now]存起来,每次有新元素入队时维护队列的单调性,之后当所有元素入队完,直接用队首的最大值进行一遍find就好了,这样就可以避免进行多次find了
尽管单调队列是用常数奇大的deque实现的,但开了O2能跑到120 ms,轻松卡到最优解第一
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#define re register
#define int long long
#define maxn 100001
using namespace std;
int f[65540],a[maxn],b[17],n,m,num,p[maxn];
int c[17];
inline void check(int x)
{
memset(c,0,sizeof(c));
int pp=m;
while(x)
{
if(x&1) c[pp]=1;
pp--;
x>>=1;
}
}
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
inline int find(int x)
{
int l=1,r=n,tot=0;
while(l<=r)
{
int mid=l+r>>1;
if(p[mid]<=x) l=mid+1,tot=mid;
else r=mid-1;
}
return tot;
}
signed main()
{
m=read();
n=read();
for(re int i=1;i<=m;i++) b[i]=read(),num+=b[i];
for(re int i=1;i<=n;i++) a[i]=read();
p[1]=a[1];
for(re int i=2;i<=n;i++) p[i]=p[i-1]+a[i];
for(re int i=0;i<=(1<<m)-1;i++)
{
deque<int> q;
for(re int j=1;j<=m;j++)
{
if(!(i&(1<<(m-j)))) continue;//这里跟楼上楼下几篇题解不太一样,这个状态转成二进制后左边第一位表示的是第一个硬币是否被选择
int k=i^(1<<(m-j));
while(q.size()&&q.back()<p[f[k]]+b[j]) q.pop_back();//跟队尾元素比较,如果比队尾大就弹出队尾,维护单调队列单调性
q.push_back(p[f[k]]+b[j]);//入队
}
//其实这里不用单调队列优化也是可以的,我们只需要存储一下最大值就好了,这样应该还能快一些,但是用单调队列优化dp的这种思路还是比较重要的
f[i]=find(q.front());//只用一遍find就好了
}
int ans=-1;
for(re int i=0;i<=(1<<m)-1;i++)
{
if(f[i]!=n) continue;//当前状态根本到不了n,就直接下一个
check(i);//将当前的状态转成二进制数
int tot=0;
for(re int j=1;j<=m;j++)
if(c[j]==0) tot+=b[j];
//如果没有被选择,那么就把它加上
if(tot>ans) ans=tot;
}
cout<<ans;
return 0;
}
【[USACO13NOV]没有找零No Change】的更多相关文章
- [USACO13NOV]没有找零No Change [TPLY]
[USACO13NOV]没有找零No Change 题目链接 https://www.luogu.org/problemnew/show/3092 做题背景 FJ不是一个合格的消费者,不知法懂法用法, ...
- 洛谷P3092 [USACO13NOV]没有找零No Change
P3092 [USACO13NOV]没有找零No Change 题目描述 Farmer John is at the market to purchase supplies for his farm. ...
- P3092 [USACO13NOV]没有找零No Change
题目描述 Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 ...
- 洛谷 P3092 [USACO13NOV]没有找零No Change
题目描述 Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 ...
- luogu P3092 [USACO13NOV]没有找零No Change
题目描述 Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 ...
- P3092 [USACO13NOV]没有找零No Change 状压dp
这个题有点意思,其实不是特别难,但是不太好想...中间用二分找最大的可买长度就行了. 题干: 题目描述 Farmer John <= K <= ), each with value .., ...
- Luogu P3092 [USACO13NOV]没有找零No Change【状压/二分】By cellur925
题目传送门 可能是我退役/NOIP前做的最后一道状压... 题目大意:给你\(k\)个硬币,FJ想按顺序买\(n\)个物品,但是不能找零,问你最后最多剩下多少钱. 注意到\(k<=16\),提示 ...
- [luoguP3092] [USACO13NOV]没有找零No Change(状压DP + 二分)
传送门 先通过二分预处理出来,每个硬币在每个商品处最多能往后买多少个商品 直接状压DP即可 f[i]就为,所有比状态i少一个硬币j的状态所能达到的最远距离,在加上硬币j在当前位置所能达到的距离,所有的 ...
- [洛谷P3092]【[USACO13NOV]没有找零No Change】
状压\(DP\) + 二分 考虑构成:\(k<=16\)所以根据\(k\)构造状压\(dp\),将所有硬币的使用情况进行状态压缩 考虑状态:数组\(dp[i]\)表示用\(i\)状态下的硬币可以 ...
随机推荐
- 有标号的DAG计数 II
Description 给定一正整数n,对n个点有标号的有向无环图(可以不连通)进行计数,输出答案mod 998244353的结果 Solution 考虑 \(O(n^2)\) DP 枚举出度为 \( ...
- [转].Net Core Web应用发布至IIS后报“An error occurred while starting the application”错误
本文转自:http://www.cnblogs.com/TomGui/p/6438686.html An error occurred while starting the application. ...
- [转] 多种方法查看Oracle SQL执行计划
本文转自:http://falchion.iteye.com/blog/616234 一.在线查看执行计划表 如果PLAN_TABLE表不存在,执行$ORACLE_HOME/rdbms/admin/u ...
- MyBatis 学习(一)
一.MyBatis 1.MyBatis 介绍(百度) MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数 ...
- ajax实现菜单联动显示信息(当选择单位的时候,动态关联出人员信息)
在jsp页面中使用onchange属性调用下面的方法: 在script中写入: function fromid(){ var from_id = $("#from_id").val ...
- zookeeper学习实践1-实现分布式锁
引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...
- 《Java并发编程实战》读书笔记(一)----- 简介
简史 早期的计算机中不包含操作系统,从头至尾都只执行一个程序,并且这个程序能访问计算机所有资源.随着计算机发展,操作系统的出现,使得计算机可以同时运行多个程序,并且每程序都在单独的进程内运行.为什么要 ...
- window.open在Safari中不能打开的问题
在调移动支付问题的时候遇到过,用window.open打开一个微信支付链接,唤醒移动支付,在IOS下死活唤醒不了,是js代码冲突问题...是click事件IOS下不兼容问题...最后定位到window ...
- Hadoop序列化程序报错
这个错误指向序列化类,注意实现的Read和Wirte顺序一定要一致,并且要使用基本类型,不要使用包装类. java.lang.Exception: java.io.EOFException at or ...
- ASPF(Application Specific Packet Filter)
ASPF ASPF(Application Specific Packet Filter)是针对应用层的包过滤,其原理是检测通过设备的报文的应用层协议信息,记录临时协商的数据连接,使得某些在安全策略中 ...