Sticks Problem
题目大意:给你一串n个数的数列a,上面的数为a1到an。我们求最大的y-x,其中,y和x满足1.x<y 2.任意的x<i<y,都有ai>ax&&ai<ay。
注释:n<=50000,ai<=100000
想法:我们很容易就想到,松弛x。那么,对于任意的x,y都必须满足这样的条件,就是说y和x之间的所有数,都大于ax。那么,我们就可以处理出任意的x右边的第一个比ax小的数的下标为r[x]。这样,我们就可以显然第知道,y必定存在于x到r[x]之间。那么,什么样的y是最大的且满足题意的呢?不难想到,就是x到r[x]之间的最大值的下标,就是y。这样,我们思考怎样才能实现这个过程?首先,我们需要求出r[x],这是n*n的,我们想优化吧,用单调队列优化,时间复杂度O(nlogn)。然后,我们对于任意的x都有一个唯一的r[x]与之对应,我们想在这段区间内求出这段区间之内的最大值,用ST求RMQ下标即可。
最后,附上丑陋的代码... ...
1 #include <iostream> 2 #include <cstdio> 3 #define N 50100 4 using namespace std; 5 int r[N],f[N][17],a[N],log[N]; 6 int main() 7 { 8 int n; 9 for(int i=2;i<=N;i++) log[i]=log[i>>1]+1;//我们可以直接处理ST中的log数组 10 while(~scanf("%d",&n)) 11 { 12 for(int i=1;i<=n;i++) 13 { 14 scanf("%d",&a[i]); 15 } 16 for(int i=n+1;i>=1;i--)//单调队列优化,那个(n+1)是极其重要的!! 17 { 18 if(a[i]>a[i+1]) r[i]=i+1; 19 else 20 { 21 int t=r[i+1]; 22 while(a[i]<a[t]) t=r[t]; 23 r[i]=t; 24 } 25 } 26 r[n+1]=-1; 27 // for(int i=2;i<=n;i++) log[i]=log[i>>1]+1; 28 for(int i=1;i<=n+1;i++)//预处理的初始化是下标 29 { 30 f[i][0]=i; 31 } 32 for(int i=1;(1<<i)<=n+1;i++) 33 { 34 for(int j=1;j+(1<<i)-1<=n+1;j++) 35 { 36 if(a[f[j][i-1]]>a[f[j+(1<<(i-1))][i-1]])//由于我们维护的是下标,所以就比较的麻烦。 37 f[j][i]=f[j][i-1];//其实我开始写的是三目运算符,但是太长了,就写if了。 38 else f[j][i]=f[j+(1<<(i-1))][i-1]; 39 } 40 } 41 int maxn=-1; 42 int len=0; 43 int maxx; 44 for(int i=1;i<=n;i++) 45 { 46 len=log[r[i]-i+1]; 47 if(a[f[i][len]]>a[f[r[i]-(1<<len)+1][len]]) maxx=f[i][len]; 48 else maxx=f[r[i]-(1<<len)+1][len];//同样,我们在查询时需要注意,我们维护的是下标。 49 maxn=max(maxn,maxx-i); 50 } 51 if(maxn<=0) printf("-1\n");//这里,我们说明:因为y>x,所以maxn==0的情况也是不满足题意的。 52 else printf("%d\n",maxn); 53 } 54 }
小结:RMQ是可以维护下标的,只是实现过程有些磨人....
1.我们需要明确注意,单调队列优化的时候,r[n+1]是坚决不能是0的??!
2.单调队列处理下标时,不可对a赋值...这种错误只有我会犯了吧。
3.RMQ中ST的思想的重要性远远大于其代码本身。