【问题描述】
奶牛在熊大妈的带领下排成了一条直队。
显然,不同的奶牛身高不一定相同……
现在,奶牛们想知道,如果找出一些连续的奶牛,要求最左边的奶牛 A 是最矮的,最右
边的 B 是最高的,且 B 高于 A 奶牛,且中间如果存在奶牛,则身高不能和 A、B 奶牛相同,
问这样的一些奶牛最多会有多少头。
从左到右给出奶牛的身高,请告诉它们符合条件的最多的奶牛数(答案可能是零、二,
但不会是一)。
【输入格式】
第一行一个数 N(2<=N<=100000),表示奶牛的头数。
接下来 N 个数,每行一个数,从上到下表示从左到右奶牛的身高(1<=身高
<=maxlongint)。
【输出格式】
一行,表示最多奶牛数。
【输入样例】Tahort.in
5
1
2
3
4
1
【输出样例】Tahort.out
4
【 样例解析 】
取第 1 头到第 4 头奶牛,满足条件且为最多。

这道题的思路如下:我们可以首先找到整个区间内最高的牛所在的位置和最矮的牛所在的位置。这样的话,答案区间就不可能越过这两头牛了,之后将区间分开递归求解即可。如果高的牛(maxn)在矮的牛(minn)前面,那么递归搜索

(l,maxn),(maxn+1,minn-1),(minn,r) ,如果矮的牛在高的牛前面,那么我们直接用maxn-minn+1更新答案,之后递归搜索(l,minn-1),(maxn+1,r)即可。

这样的话问题就转化成了如何快速求任意一段区间内的最大最小值的位置。这是一个典型的RMQ问题,我们选择使用st表解决。既然只求最大最小值的位置,那么我们就可以不使用st表存值,这样不仅好写而且时间还短。具体的做法就是我们自定义函数来比较编号,每次比较大小结束之后记录当前区间内最大(小)值的位置即可。这样每次递归访问的时候,我们甚至可以做到O(1)。

这道题有很多地方还是非常坑的,比如说你写一个十分正确的RMQ在Lemon或者本机上运行都会导致RE,据说可能是因为递归层数过多而爆栈,这个自己本人调试也调不出来,你只会看到程序在输入所有数据之后报错。可以使用vijos代测,但是我的程序前几次提交全部TLE,结果最后采用了一个优化,就是如果递归的区间长度小于当前的答案就直接返回无需搜索。但还是不行……最后发现是因为开了全局变量的缘故,开成局部变量就过了……蒟蒻至今搞不明白是为什么。

最后上一下代码吧。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
using namespace std;
const int N = ,M = ;
typedef long long ll;
int n,h[N],max1[N][M],min1[N][M],ans1;
int read()
{
int ans = ;
char ch,last = ' ';
ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') ch = last;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
if(last == '-') ans = -ans;
return ans;
}
int fmax(int c,int d)//自定义比较编号的函数
{
if(h[c] > h[d] || (h[c] == h[d] && c < d)) return c;
else return d;
}
int fmin(int c,int d)
{
if(h[c] < h[d] || (h[c] == h[d] && c > d)) return c;
else return d;
}
void ask(int l,int r)
{
if(l >= r || ans1 >= r-l+) return;//这个优化可以省很多时间
int k = log2(r-l+);//注意这里开cstdlib
int g = << k;
int maxn = fmax(max1[l][k],max1[r-g+][k]);
int minn = fmin(min1[l][k],min1[r-g+][k]);//就是这两行坑了无数次!!!
if(maxn == minn) return;
if(maxn > minn)
{
ans1 = max(ans1,maxn-minn+);//更新并递归
ask(l,minn-);
ask(maxn+,r);
return;
}
else
{
ask(l,maxn);
ask(maxn+,minn-);
ask(minn,r);
return;
}
}
int main()
{
n = read();
rep(i,,n)
{
h[i] = read();
max1[i][] = i;
min1[i][] = i;
}
int q = log2(n);
rep(j,,q)
{
for(int i = ;i+(<<j)-<=n;i++)
{
max1[i][j] = fmax(max1[i][j-],max1[i+(<<(j-))][j-]);
min1[i][j] = fmin(min1[i][j-],min1[i+(<<(j-))][j-]);
}//st表求最大最小值
}
ask(,n);
printf("%d\n",ans1);
return ;
}

奶牛排序——RMQ的更多相关文章

  1. 牛客假日团队赛2 H.奶牛排序

    链接: https://ac.nowcoder.com/acm/contest/924/H 题意: 农夫JOHN准备把他的 N(1 <= N <= 10,000)头牛排队以便于行动.因为脾 ...

  2. BZOJ2815:[ZJOI2012]灾难(拓扑排序,LCA)

    Description 阿米巴是小强的好朋友. 阿米巴和小强在草原上捉蚂蚱.小强突然想,如果蚂蚱被他们捉灭绝了,那么吃蚂蚱的小鸟就会饿死,而捕食小鸟的猛禽也会跟着灭绝,从而引发一系列的生态灾难. 学过 ...

  3. POJ -3190 Stall Reservations (贪心+优先队列)

    http://poj.org/problem?id=3190 有n头挑剔的奶牛,只会在一个精确时间挤奶,而一头奶牛需要占用一个畜栏,并且不会和其他奶牛分享,每头奶牛都会有一个开始时间和结束时间,问至少 ...

  4. USACO 2001 OPEN

    第1题 绿组. 奶牛接力赛[relay] 题目描述 农夫约翰已经为一次赛跑选出了K(2≤K≤40)头牛组成了一支接力队.赛跑在农夫约翰所拥有的农场上进行,农场的编号为1到Ⅳf4≤Ⅳ< 800), ...

  5. POJ2376 Cleaning Shifts

    题意 POJ2376 Cleaning Shifts 0x50「动态规划」例题 http://bailian.openjudge.cn/practice/2376 总时间限制: 1000ms 内存限制 ...

  6. POJ 2010 Moo University - Financial Aid (优先队列)

    题意:从C头奶牛中招收N(奇数)头.它们分别得分score_i,需要资助学费aid_i.希望新生所需资助不超过F,同时得分中位数最高.求此中位数. 思路: 先将奶牛排序,考虑每个奶牛作为中位数时,比它 ...

  7. 【贪心】洛谷P1607 [USACO09FEB]庙会班车Fair Shuttle 题解

        不是很容易写出正解的贪心问题. 题目描述 Although Farmer John has no problems walking around the fair to collect pri ...

  8. poj3171 Cleaning Shifts

    传送门 题目大意 有一个大区间和n个小区间,每个小区间都有一个代价,求最少付出多少代价可以使得小区间完全覆盖大区间. 分析为了方便起见我们先将s变为2,其它的位置都对应更改以便后期处理.我们考虑以t1 ...

  9. 【POJ - 2376】Cleaning Shifts(贪心)

    Cleaning Shifts Descriptions: 原文是English,我这就直接上Chinese了,想看原文的点一下链接哦 大表哥分配 N (1 <= N <= 25,000) ...

随机推荐

  1. 牛客练习赛1 矩阵 字符串二维hash+二分

    题目 https://ac.nowcoder.com/acm/contest/2?&headNav=www#question 解析 我们对矩阵进行二维hash,所以每个子矩阵都有一个额hash ...

  2. 洛谷——P1746 离开中山路

    P1746 离开中山路 题目背景 <爱与愁的故事第三弹·shopping>最终章. 题目描述 爱与愁大神买完东西后,打算坐车离开中山路.现在爱与愁大神在x1,y1处,车站在x2,y2处.现 ...

  3. sugar与阿龙的互怼(第一季)

    §   第一季 回家风波 高考了,啦啦啦~ 快要高考了,显然sugar很伤心. 显然不是因为快要考试了sugar才伤心的. 那为什么??? 因为他们都回家了,但是sugar和他的小伙伴们都不回家!!! ...

  4. PC下ubuntu查找PC串口并加入用户组

    1. 查看ttyS0隶属的组:ls -l /dev/ttyS0  //发现隶属于dialout组 输出: crw-rw---- 1 root dialout 4, 64  9月  9 08:23 /d ...

  5. Set 技巧之一

    我们知道set中 用set<int,int>S; S.lower_bound(x): 查找Set中 第一个>=x的数,返回结果是指针. S.upper_bound(x):查找Set中 ...

  6. 字符串哈希hash

    题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...

  7. Maven使用site-deploy(site:deploy)部署通过site生成的文档(Tomcat-WebDAV)

    Maven可以通过site生成项目的帮助文档,并且格式为html,那么可以通过site-deploy把文档部署到远端,部署方式支持HTTP/FTP/SCM/WebDAV等. 更多部署方案,参考:htt ...

  8. excel转换html

    利用POI解析excel,转换成html,支持各种版本的excel.支持自定义样式.支持行列合并 需要用到的jar public class Excel2Html { /** * 读取Excel并转换 ...

  9. FIREDAC字段类型映射

    为什么需要字段类型映射? 作为通用型数据引擎的FIREDAC或者UNIDAC,驱动某一种数据库以后,总有一些数据库的一些字段类型,数据引擎不能识别,反应到程序中就是数据引擎不能正确地读取该字段的值 . ...

  10. CentOS下常用的 19 条命令

    玩过Linux的人都会知道,Linux中的命令的确是非常多,但是玩过Linux的人也从来不会因为Linux的命令如此之多而烦恼,因为我们只需要掌握我们最常用的命令就可以了.当然你也可以在使用时去找一下 ...