您的位置:首页 > 其它

poj 2452 RMQ(Sticks Problem)

2015-02-24 20:54 239 查看
题意:给出n个互不相同的数字,要求一个最大的子段,使得该子段内所有数(除了两端以外),值都在两端的数字之间(比左端值大,比右端值小)。

分析:(http://www.cnblogs.com/rainydays/archive/2012/07/10/2584576.html)先对整个数组分别构造最大值RMQ和最小值RMQ的数组。然后,枚举子段起点,对于每个起点求出这个起点是区间最小值的最远终点(用二分查找)。然后在这个区间内找到最大值位置,从起点到最大值位置这个区间就是起点所对应的符合题意的最大区间。枚举过所有的起点之后,结果就求出来了。其中二分还是比较灵活。如果不用hash的话,那么rmq的时候保存下标而不是值即可。

discuss里有人说单调栈甚至暴搜也能AC。

#include <stdio.h>
#include <string.h>
#include <math.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define N 50005
int dmax
[20],dmin
[20],s
,hash[100005];
int n;
void st(){
int i,j;
int k = log((double)n+1)/log(2.0);
for(i = 1;i<=n;i++)
dmax[i][0] = dmin[i][0] = s[i];
for(j = 1;j<=k;j++)
for(i = 1;i+(1<<j)-1<=n;i++)
dmax[i][j] = max(dmax[i][j-1], dmax[i+(1<<(j-1))][j-1]),
dmin[i][j] = min(dmin[i][j-1], dmin[i+(1<<(j-1))][j-1]);
}
int querymin(int a,int b){
int k = log((double)(b-a+1))/log(2.0);
return min(dmin[a][k], dmin[b-(1<<k)+1][k]);
}
int querymax(int a,int b){
int k = log((double)(b-a+1))/log(2.0);
return max(dmax[a][k], dmax[b-(1<<k)+1][k]);
}
int search(int x,int low,int high){
int j,mid;
int base = low-1;
while(low <= high){
mid = (low+high)>>1;
j = querymin(base,mid);
if(j < x)
high = mid-1;
else
low = mid+1;
}
return high;
}
int main(){
while(scanf("%d",&n) != EOF){
int i,j,end,res=0;
memset(hash,0,sizeof(hash));
for(i = 1;i<=n;i++){
scanf("%d",&s[i]);
hash[s[i]] = i;//由于这些数各不相同,所以可以用hash
}
st();
for(i = 1;i<n;i++){
end = search(s[i],i+1,n);//这个二分还是比较灵活的
j = hash[querymax(i,end)]-i;
res = max(res,j);
}
printf("%d\n",(!res)?-1:res);
}
return 0;
}


不用hash,rmq保存下标:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 50005
#define M 100005
int s
,n,dmin
[20],dmax
[20];
void st(int n){
int i,j,k = log((double)n)/log(2.);
for(i = 1;i<=n;i++)
dmin[i][0] = dmax[i][0] = i;
for(j = 1;j<=k;j++)
for(i = 1;i+(1<<j)-1<=n;i++){
if(s[dmin[i][j-1]] < s[dmin[i+(1<<(j-1))][j-1]])
dmin[i][j] = dmin[i][j-1];
else
dmin[i][j] = dmin[i+(1<<(j-1))][j-1];

if(s[dmax[i][j-1]] > s[dmax[i+(1<<(j-1))][j-1]])
dmax[i][j] = dmax[i][j-1];
else
dmax[i][j] = dmax[i+(1<<(j-1))][j-1];
}
}
int qmax(int a,int b){
int k = log((double)(b-a+1))/log(2.);
if(s[dmax[a][k]] < s[dmax[b-(1<<k)+1][k]])
return dmax[b-(1<<k)+1][k];
return dmax[a][k];
}
int qmin(int a,int b){
int k = log((double)(b-a+1))/log(2.);
if(s[dmin[a][k]] > s[dmin[b-(1<<k)+1][k]])
return dmin[b-(1<<k)+1][k];
return dmin[a][k];
}
int search(int b,int low,int high){
int mid;
while(low <= high){
mid = (low+high)>>1;
if(s[qmin(low,mid)] < b)
high = mid-1;
else
low = mid+1;
}
return high;
}
int main(){
while(scanf("%d",&n)!=EOF){
int i,j;
int res = -1;
for(i = 1;i<=n;i++)
scanf("%d",&s[i]);
st(n);
for(i = 1;i<n;i++){
j = search(s[i],i+1,n);
int tmp = qmax(i,j);
res = max(res,tmp-i);
}
printf("%d\n",!res?-1:res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: