其实我是点单调队列的标签进来的,之后看着题就懵逼了

于是就去题解里一翻,发现楼上楼下的题解说的都好有道理,
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;
}

转载于:https://www.cnblogs.com/asuldb/p/10207855.html

【[USACO13NOV]没有找零No Change】相关推荐

  1. Luogu3092 [USACO13NOV]没有找零No Change (状压DP)

    将金币状压,然后就没多说的了. #include <iostream> #include <cstdio> #include <cstring> #include ...

  2. C语言/860.(柠檬水找零)Lemonade Change

    先上题目 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 5 美元.10 美元或 20 美元 ...

  3. C++coin change 硬币找零(附完整源码)

    coin change 硬币找零 coin change 硬币找零算法的完整源码(定义,实现,main函数测试) coin change 硬币找零算法的完整源码(定义,实现,main函数测试) #in ...

  4. python 找零问题 动态规划

    题目描述: 现有的钱币:coins=[1,2,5,7,10] 找零:change(假定为正整数) 求解:如何用最少的钱币进行找零 分析:可以使用动态规划 比如找零8元,可以将问题进行分解 dp[8]= ...

  5. python找零_python 找零问题 动态规划

    题目描述: 现有的钱币:coins=[1,2,5,7,10] 找零:change(假定为正整数) 求解:如何用最少的钱币进行找零 分析:可以使用动态规划 比如找零8元,可以将问题进行分解 dp[8]= ...

  6. python找零_用python实现零钱找零的三种方法

    1.递归(recursion)def coins_changeREC(coin_values, change): """ 递归实现零钱找零 ""&qu ...

  7. Python贪心算法解决收银员找零问题

    场景描述 在超市结账时,假设只有1分.5分.1角.3角.5角.1元的硬币,如果需要找零钱,给定需要找的零钱数目,使收银员找给顾客的硬币数量最少,运行程序如图: 知识补充  贪心算法是指在当前问题求解中 ...

  8. C#LeetCode刷题之#860-柠檬水找零(Lemonade Change)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4036 访问. 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾 ...

  9. Coin Change【硬币找零】

    一.题目 英文:Coin Change 中文:硬币找零 二.内容要求 英文:You are given coins of different denominations and a total amo ...

最新文章

  1. 恢复脚本(导入数据库)
  2. 特征值_陶哲轩数学发现的故事 | 特征值特征向量等式
  3. Hbase 查看 rowkey在哪个region中
  4. 你的护城河在哪?老程序员的一些2016感悟
  5. php通过数组存取mysql查询语句的返回值
  6. CentOS7如何关闭防火墙
  7. 无显示仍然发挥树莓派——VNCserver设定
  8. Python自然语言处理相,新词发现,主题模型,隐马尔模型词性标注,Word2Vec,情感分析...
  9. C语言 最小二乘 向量旋转 欧拉方法求洛伦兹方程
  10. Java--对象的克隆
  11. 基于dpdk的用户态协议栈f-stack实现分析
  12. javaSocket网络编程
  13. Windows10批处理文件中用regedit导入注册表文件失败的原因和解决办法
  14. Intellij IDEA 设置字体加粗
  15. Windows10超级管理员账号权限受限的问题
  16. 电感设计中的细节问题:磁芯损耗、线圈设计
  17. 前端学习笔记 - px,em,rem,%,vw,vh,vm
  18. HTML中Table标签的属性及应用
  19. 太阳的光和灯光有什么区别_太阳光跟星光是一样的吗?两者有什么差异?
  20. php搜索引擎详细代码

热门文章

  1. 千万数据去重_如何在 1 秒内做到大数据精准去重?
  2. pytorch CNN
  3. 模型保存的方法-----仅保存权重
  4. 屏幕坏点检测图片_【沙发管家】教你自己测试智能电视屏幕
  5. 怎样把照片中的头像扶正_一个男人的微信头像,往往暴露了“人品”,你是哪一种?...
  6. Python学习入门基础教程(learning Python)--4.3 Python的for嵌套
  7. VS2012下基于Glut OpenGL GL_POLYGON_STIPPLE示例程序:
  8. OpenGL常见函数功能查询
  9. mysql nginx 无法访问_nginx可以启动成功却无法访问
  10. 项目周期一般多久_收藏!布袋除尘器清灰周期一般多久合适?