前言

感觉自己就没弄懂过 单调栈\队列相关的优化... ...

题目

在炽热的核熔炉中,居住着一位少女,名为灵乌路空。
据说,从来没有人敢踏入过那个熔炉,因为人们畏缩于空所持有的力量——核能。
核焰,可融真金。
 
咳咳。
每次核融的时候,空都会选取一些原子,排成一列。然后,她会将原子序列分成一些段,并将每段进行一次核融。
一个原子有两个属性:质子数和中子数。
每一段需要满足以下条件:
1、同种元素会发生相互排斥,因此,同一段中不能存在两个质子数相同的原子。
2、核融时,空需要对一段原子加以防护,防护罩的数值等于这段中最大的中子数。换句话说,如果这段原子的中子数最大为x,那么空需要付出x的代价建立防护罩。求核融整个原子序列的最小代价和。

Input

第一行一个正整数N,表示原子的个数。
接下来N行,每行两个正整数pi和ni,表示第i个原子的质子数和中子数。

Output

输出一行一个整数,表示最小代价和。

Sample Input

5
3 11
2 13
1 12
2 9
3 13

Sample Output

26

【数据范围】

对于20%的数据,1<=n<=100
对于40%的数据,1<=n<=1000
对于100%的数据,1<=n<=10^5,1<=pi<=n,1<=ni<=2*10^4

分析

最开始自己以为是贪心(不是贪心至少也能骗到分吧),结果没想到暴零了.../暴风哭泣

参考题解\博客:https://blog.csdn.net/doyouseeman/article/details/53121206

这道题有一个很显然的dp方程,f[i]=f[j]+max(b[j+1…i])。 
我们设后面的为g,那么很明显g是递增的。 
那么用一个队列来维护后面的那个东西。 
因为要满足一段里面元素不重复,所以要求一个l[i]表示i往左最远扩展到的节点。 
那么每次,如果队首的位置小于l[i]那么head++,如果队尾的b小于等于当前的b[i],那么tail–(因为要像一个单调栈一样,有高的就把它踢掉)。(要保证当前这个队列里面所有的值都合法)。 
那么现在i就可以进队了。 
现在就有两种情况: 
1、这个队列只有一个数,就是刚刚加进来的那个数,那么就直接更改一下队列中的值就好了。 
2、这个队列中不止一个数,那么除了要更改刚刚进来的数的值,现在还要更新一下最小的值(用一个set来维护),现在的head因为l[i]不一样了,所以初始的高度可能会不一样,所以需要重新入队一次。

另一个JZOJ的题解:

首先来想最简单的动态规划,通过第一个数的限制,我们可以得到每个位置的状态可以从哪 些位置转移过来,得到如下形式的式子: f(i) = ????=?[?] ?−1 (?[? + 1][?] + ?[?]) 其中 s[i][j]表示从 i 到 j 的最大值,l[i]表示 i 位置最多向左走到哪里。 然后套路一波,用个单调递减的单调队列,每次将队头不合法的依次踢掉,然后我们来想想, 这样我们只是得到了可以转移过来的状态集,那么如何维护答案呢?

观察下图:

现在我们的 i 在位置 8 上,红色框表示 i 向左最多到达的位置(即 2 与 8 的 p[i]是一样的) 可以看出,除了队头之外,其他的在单调队列里的元素的贡献都是从前面一个位置的 f 转移 而来的(因为 f 是单调不减的),而队头的则是依赖于 l[i]的。 假设当前的队列为:a[head. .tail]且∀head ≤ i < tail, a[i] < a[i + 1] 那么当前点的答案为:max(????=ℎ???+1 ???? (ℎ[?[?]] + ?[?[? − 1]]) , h[a[head]] + f[l[i] − 1]) 观察到每次我们移动一个点是有许多没有变的状态的,每个元素进一次出一次,于是我们用 堆或者其他数据结构来维护队列中每个元素的贡献,对于队头特殊处理。 时间复杂度O(n ???2n)

考试贪心瞎搞代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;//记得算空间、开ll
const int MAXN=1e5;
bool vis[MAXN+5];
int a[MAXN+5],b[MAXN+5];
int n;
ll ans,Max;
int main()
{//freopen("array.in","r",stdin);//freopen("array.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d%d",&a[i],&b[i]);//printf("%d vis:%d\n",a[i],vis[a[i]]);if(!vis[a[i]])//没有出现过 {vis[a[i]]=1;Max=max(Max,(ll)b[i]);}else//出现过 {ans+=Max;//累加前一段的答案 Max=b[i];memset(vis,0,sizeof(vis));vis[a[i]]=1;}//printf("Max:%d ans:%d\n",Max,ans);} ans+=Max;//累加最后一段的答案 printf("%lld",ans);return 0;
}
/*
可行的时间复杂度:n or nlogn
贪心策略:
1.大的数尽量去包含其他数
2. 遇到出现过的数就被迫分一段
3.还好自己出了些有用的数据,发现了有一些bug,汗...
*/

AC代码

#include<cstdio>
#include<set>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;//记得算空间、开ll
const int MAXN=1e5;
bool vis[MAXN+5];
int a[MAXN+5],b[MAXN+5],data[MAXN+5],hou[MAXN+5],l[MAXN+5];
int sum[MAXN+5],id[MAXN+5],f[MAXN+5];
int n,m,k,head,tail;
int ans,Max;
multiset<int> t;
int main()
{//freopen("array.in","r",stdin);//freopen("array.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);//hou[a[i]]:第i个数a[i]第一次出现的位置 //l[i]:第i个数能向左边到的最远位置(没有与自己相同的) for(int i=1;i<=n;i++)l[i]=hou[a[i]]+1,hou[a[i]]=i;for(int i=1;i<=n;i++)l[i]=max(l[i-1],l[i]);//左端点取最靠右的 head=1;for(int i=1;i<=n;i++){k=i-1;//如果队首的位置小于l[i]那么head++while(head<tail&&id[head+1]<l[i]){t.erase(t.find(sum[head]));head++;}//如果队尾的b小于等于当前的b[i],那么tail--//(因为要像一个单调栈一样,有高的就把它踢掉)while(head<=tail&&b[i]>data[tail]){t.erase(t.find(sum[tail]));k=id[tail];tail--;}//处理完后现在i就可以进队了data[++tail]=b[i];id[tail]=k;/*若这个队列中不止一个数,那么除了要更改刚刚进来的数的值,现在还要更新一下最小的值(用一个set来维护),现在的head因为l[i]不一样了,所以初始的高度可能会不一样,所以需要重新入队一次*/if(head!=tail){sum[tail]=f[id[tail]]+data[tail];t.insert(sum[tail]);t.erase(t.find(sum[head]));}sum[head]=f[l[i]-1]+data[head];t.insert(sum[head]);f[i]=*t.begin();}printf("%d",f[n]);return 0;
}

【贪心-单调栈】中山纪念中学暑期游Day12——灵知的太阳信仰相关推荐

  1. 【2019-游记】中山纪念中学暑期游Day12

    前言 今日,上天为我使用了"暴零体验卡"... ... 欢迎来到本期特别节目:[暴零是怎样炼成的] Day12杂记 早上吃饭第一次吃到红豆沙面包,虽然挺好吃的,但是好难啃(奇葩食堂 ...

  2. 【贪心】中山纪念中学暑期游Day12——少女觉

    前言 哇这个坑爹题!!!考试时想不到正解,考试后知道了正解却打不对 啊啊啊啊 题目 在幽暗的地灵殿中,居住着一位少女,名为古明地觉. 据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力 ...

  3. 【2019-游记】中山纪念中学暑期游Day2

    前言 不知不觉到了第二天,今天没怎么下雨,对于经历了两天大雨的自己来说:心情舒畅qwq 可是尽管"心情再舒畅",都不能挽救考撇了的事实--努力改题吧 Day2杂记 早上依旧起不来. ...

  4. 【2019-游记】中山纪念中学暑期游Day3

    前言 今天没有考试,专门讲课,听不懂的同学还可以回机房 瞎搞 ,感觉安排的还可以,至少时间还是挺充裕的,只是讲解的内容太多了,消化不完QAQ... Day3杂记 早上依旧没有早起...三天过去了,我连 ...

  5. 【2019-游记】中山纪念中学暑期游Day4

    前言 夏天很快就要过去啦 而我还没有和他握过手 今天真的太忙啦,被一道题目折磨了好久 Day4杂记 早上两个面包+一碗皮蛋瘦肉粥,喝粥的时候感觉是"""舀一舀,抽奖赢大礼 ...

  6. 【2019-游记】中山纪念中学暑期游Day5

    前言 前几天刮大风.下暴雨,这几天阳光明媚,今天开始有点热了 这里的天气就像一个敢爱敢恨的小姑娘 好想在夏天痛痛快快地玩耍 Day5杂记 早上依旧起晚,不起晚似乎就不是没有闹铃的我了...简单吃完早饭 ...

  7. 【折半搜索-经典题目】中山纪念中学暑期游Day13——【GDOI2017模拟8.15】Buy

    前言 考试时有道题目用到了[折半搜索] 老师推荐了这道经典题目让大家练习[前后部分算法不同]的题目 虽然不知道我有没有时间做,好歹先把题目记录一下,免得以后找不到了qwq 题目 Input Outpu ...

  8. 【2019-游记】中山纪念中学暑期游Day6

    前言 今天的安排是--听课![数据结构]专题,花了一早上和一下午,晚上在搞一个兄弟自己出的题目(贼坑),于是时间又没了QAQ... 真心觉得时间怎么都不够用啊咧... Day6杂记 早上还是没有早起成 ...

  9. 【2019-游记】中山纪念中学暑期游Day1

    前言(前往纪中的一天) 本来最开始不想报名的...后来脑子一抽...就踏上了前往广东的道路... 早上6点爬起来赶飞机,飞机下降的时候耳朵贼疼orz,还好挺过来了/思考:压强的原因? 过了大约两小时, ...

最新文章

  1. android 按键kl文件,Android添加新按键
  2. jquery/css实现步骤条
  3. MAC IOS ssh 连接下修改环境变量
  4. Linux 进程间通讯方式 pipe()函数
  5. 百度爬虫爬到虚拟链接 网站被黑_什么是网络爬虫?原理是什么?种类有多少?...
  6. Harmony OS — PageSliderIndicator滑动页面指示器
  7. 类__slots__与__dict__用法
  8. 后台审批功能 销售发货单 生成 销售出库单 java NC633 接口开发
  9. ftp连不上linux虚拟机,cuteftp连不上Linux虚拟机的解决方案
  10. 自定义控件属性英文类别
  11. FatSecret Platform API
  12. python打开ie浏览器_python+selenium启动IE浏览器
  13. 酷狗及一些播放软件收费歌曲下载方法
  14. Unity摄像头仿真调研(svl)
  15. 二级计算机密码怎么设置,如何设置电脑密码
  16. 移动管家汽车手机蓝牙无钥匙解锁方案
  17. 博学谷 java_博学谷javaee在线就业班2020
  18. 常用的正则表达式判断手机号邮箱等
  19. Java语言底层架构
  20. 重装助手教你如何在Windows 10中自动执行常见维护任务

热门文章

  1. 怎样用计算机告白,计算机学科的告白情话
  2. 看看我们熟知的17个行业如何被互联网所颠覆
  3. 「AI芯片公司」比特大陆的路线图上,除了四款TPU还有在这三个产业落地的野心
  4. SAP MM 供应商无英文名称,ME21N里却带出了英文名字?
  5. 视频教程-Project-规划项目(基本操作)-Office/WPS
  6. 推荐3个网页设计在线配色网站
  7. 计算机专业哪些课程好难,计算机专业课程有哪些 学计算机难不难
  8. Matlab 基础03 - Matlab的开源数据集- 数据集列表
  9. Styled-Components
  10. SpringBoot 中使用HikariPool 报错Possibly consider using a shorter maxLifetime value.