Cpp环境【SDUT1128】【Code[VS]1809】【CQYZOJ1823】河床
来源:互联网 发布:网络电玩游戏平台 编辑:程序博客网 时间:2024/05/12 01:55
【问题描述】
地理学家们经常要对一段河流进行测量分析。他们从上游开始向下游方向等距离地选择n(n<=30000)个点测量水位深度。得到一组数据a1,a2,…,an,回到实验室后数据分析员根据需要对数据进行分析,发掘隐藏在数据背后的规律。
最近,乌龙博士发现某种水文现象与河床地势有关,于是他指示分析员要找出一段河流中最大高低起伏差不超过K(1<=K<=100)的最长的一段。这看似一个简单的问题,由于任务紧急,分析员来求助于你,并告诉你博士的所有数据都精确到个位。
【输入格式】
第一行包含两个整数N和K,分别表示测量点的个数和博士要求的最大水深度(也就是河床的地势差)。
第二行包含N个整数,表示从上游开始依次得到的水位深度di(1<=i<=n,0<=di<=32767)
【输出格式】
一个整数m,表示最长一段起伏不超过K的河流长度,用测量点的个数表示
【输入样例】
6 2
5 3 2 2 4 5
【输出样例】
4
【数据范围】
30%的数据,满足:1<=n<=5000;
50%的数据,满足:1<=n<=30000,符合条件的最长连续序列长度不超过100;
100%的数据,满足:1<=n<=30000,符合条件的最长连续序列长度不超过n;
【来源】
从第2个测量点到第5个测量点之间的一段,即3 2 2 4,起伏最大为2。
【原题传送矩阵】
山东理工大学ACM题库 1128
Code[VS]题库 1809 传送矩阵
CQYZOJ 1823 传送矩阵
【思路梳理】
看到网上很多人的题解都是交的暴力搜索代码,直接从1~n来枚举起点,看此时能够实现的最长长度。算法是没有任何问题的,但是有追求的ACMer不应该止步于此(滑稽脸)。笔者此处提供更为高效的滑动窗口算法,供读者们茶余饭后笑谈。
简单整理一下可以将题目简化成如下的形式:在线性序列上,求最长的一段,使得该段中最大值与最小值的差不超过一个给定定值k。线段的最大长度是我们所求值。典型的变长滑动窗口问题。
设置两个滑动窗口进行存储,一个最大队,一个最小队。不断地将线性序列的元素加入到两个滑动窗口中,直到最大队队首highest与最小队队首元素lowest的差值超过了给定值k。
此时,我们就确定一下highest与lowest的相对位置。为了保证我们剩下来的滑动窗口尽可能的长,那么我们应该让highest与lowest两者当中较靠左边的一个,让它离开滑动窗口,并更新两者。如此反复维护这个滑动窗口,使得highest与lowest的差值不超过k。
在让新的元素进入滑动窗口以前,更新一次我们的答案ans即可。
笔者语拙,更多说明详见注释。
【Cpp代码】
#include<queue>#include<cstdio>#include<iostream>#define maxn 30005using namespace std;int n,k,last=1;struct data{int height,id;}a[maxn];//滑动窗口中元素两个属性:距离上游的位置和深度。//一个height用于维护滑动窗口,另一个id用于计算ansstruct cmp1{bool operator()(data a,data b){return a.height<b.height;}};//定义最大队的仿函数struct cmp2{bool operator()(data a,data b){return a.height>b.height;}};//最小队仿函数void solve(){ int ans=1,last=1;//last:当前滑动窗口最左侧元素的id,ans最小值应该是1,只有1个元素是合法解 priority_queue<data,vector<data>,cmp1>q1; priority_queue<data,vector<data>,cmp2>q2; q1.push(a[1]);q2.push(a[1]);//值得强调的是,两个滑动窗口维护的是同一段序列! data highest=q1.top(),lowest=q2.top(); for(int i=2;i<=n;i++) { q1.push(a[i]);q2.push(a[i]); highest=q1.top(),lowest=q2.top();//新元素进入滑动窗口后应该更新这两个元素的值 while(highest.height-lowest.height>k)//当该段序列的起伏差大于了k时 { if(highest.id<=lowest.id)//最大队队首元素靠左,根据贪心的思想应该使得滑动窗口尽可能长 { last=max(last,highest.id+1);//注意+1,highest元素是要出滑动窗口的 q1.pop(); } if(highest.id>lowest.id)//最小队队首元素靠左 { last=max(last,lowest.id+1); q2.pop(); } highest=q1.top();//不忘再次更新 lowest=q2.top();//这一次是可以省略的 } ans=max(ans,i-last+1); } printf("%d",ans);}int main(){// freopen("in.txt","r",stdin); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i].height),a[i].id=i; solve();}
- Cpp环境【SDUT1128】【Code[VS]1809】【CQYZOJ1823】河床
- Cpp环境【Code[VS]5226】物品选取
- Cpp环境【CQYZOJ1836】【Code[VS]5230】猴子
- Cpp环境【Code[VS]4175】【CQYZOJ1824】收费站
- Cpp环境【Code[VS]5227】【JSOI2010】盛夏的果实
- Cpp环境【Tyvj1011】【Code[VS]1169】传纸条
- Cpp环境【Code[VS]1084】【NOIP2003普及组】乒乓球
- Cpp环境【CQYZOJ1496】【Code[VS]5287】搬家大冒险
- Cpp环境【TYVJ1153】【Code[VS]4093】【CQYZOJ16874】 间谍网络
- Cpp环境【NOIP2006提高组】【Code[VS]1155】【Vijos1399】 金(精)明的预算
- Cpp环境【NOIP2015 D1P2】【Viijos1979】【Code[VS] 4511】【CQYZOS3198】 信息传递
- Cpp环境【NOIP2010提高组】【Vijos1777】【Code[VS]1066】【CQYZOJ1793】引水入城
- Cpp环境【NOIP2003 P3】【Vijos1100】【Code[VS]1090】【CQYZOS2816】加分二叉树
- 河床
- 河床
- 河床
- 河床
- VS Code配置Matlab环境
- redis常用命令及高级应用之键值的相关命令
- 【USACO4.4.3】重叠的图像(DAG图的拓扑排序)
- makefile初级基础
- Hibernate的手动配置+手动增删改数据
- linux expect详解(ssh自动登录)
- Cpp环境【SDUT1128】【Code[VS]1809】【CQYZOJ1823】河床
- 贪吃蛇大作战
- Android自定义View——实现字母导航栏
- POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结
- HTTP 302问题
- linux 中php以及nginx的重启命令
- SQL那些事儿(三)----和小伙伴们做武大游
- frameset框架
- 形象易懂讲解算法II——压缩感知