LNSYOJ#204谁是天才【RMQ理解+单调栈】【做题报告】

这是一道RMQ水题,因为本蒟蒻居然一A

题目描述

   张大牛:“我是天才!”

大肥熊:“你为什么是天才?”

张大牛:“你随便给我一个单词(大小写字母组成)长度为NN,去掉MM个字符后,我能知道字典序最小的字符串是什么样子的”

大肥熊:“换过来,现在假设这个字典序最小的字符串中第aiai个字符在原串中的位置为pospos,那么原串中区间[poski,pos+ki][pos−ki,pos+ki]中字典序最大的字符是什么?”

张大牛又被难倒了。现在这个难倒天才的题目交到你手上了。

注:区间[poski,pos+ki][pos−ki,pos+ki]超过原字符串的边界,按照原字符串的边界处理。原串的整个区间为[1,N][1,N],如果pospos可以取多个值,按照最靠前的位置计算。

 

输入格式

第一行M,TMM,T。M如题意,TT为TT组询问。

第二行为一个由大、小写字母组成的字符串。串的长度NN>M>0N(N>M>0)。

接下来TT行每行两个正整数aiki1aiNM1kiNai,ki(1≤ai≤N−M),(1≤ki≤N)。

输出格式

T行,每行对询问给出一个答案。

样例一

input

20 2
abcdefghijklmnopqrstuvwxyz
5 20
3 3

output

y
f

限制与约定

对于100%的数据,N105,T105N≤105,T≤105

时间限制1s1s

空间限制256MB

这道题呢,涉及到两个知识点

1.单调栈+贪心

这个比较好理解,但是本蒟蒻还是询问了同桌大佬@lizitong才明白,这个的思路就是,每次来一个字符串,就从最顶上开始弹,只要顶上比当前大,就弹,然后维护一个cnt,使之只弹m次,最后剩下的一定是最优解,这个是比较纯粹的单调栈

这个的模板好像没有,我写的习惯就是用while循环维护

2.RMQ

RMQ适合于维护区间最值,预处理O(n),询问O(1)

这个属于ST(倍增)算法,就是一次跳2的j次个,和lca比较像,f[i][j]表示的是以i为起点,跳2的j次个,这个区间的最值,询问的时候只要从两个方向覆盖就OK

注意有的地方是否要+1-1,这个也比较好理解

 

然后呢这道题在单调栈弹栈入栈时候维护下位置就OK,然后再询问,是不是很水?

模板在此

1 for(int i=1;i<=n;i++)f[i][0]=a[1];
2 for(int j=1;j<=log2(n);j++)
3     for(int i=1;(i+(1<<j)-1)<=n;i++)
4         f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
5 lg=log2(r-l+1);
6 printf("%c\n",max(f[l][lg],f[r-(1<<lg)+1][lg]));

代码在此,

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 int n,m,t,top,cnt,a,k;
 7 int pos[100111];
 8 char s[100111],stk[100111],f[100111][20];
 9 int main()
10 {
11     //freopen("misaki.in","r",stdin);
12     scanf("%d%d%s",&m,&t,s+1);
13     n=strlen(s+1),stk[++top]=s[1],pos[1]=1,f[1][0]=s[1];
14     for(int i=2;i<=n;i++)
15     {
16         while(top-1>=0 && stk[top]>s[i] && cnt+1<=m)top--,cnt++;
17         stk[++top]=s[i],pos[top]=i;
18         f[i][0]=s[i];
19     }
20     for(int j=1;j<=log2(n);j++)
21         for(int i=1;(i+(1<<j)-1)<=n;i++)
22             f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
23     for(int i=1;i<=t;i++)
24     {
25         scanf("%d%d",&a,&k);
26         int l=max(1,pos[a]-k),r=min(n,pos[a]+k),lg=log2(r-l+1);
27         printf("%c\n",max(f[l][lg],f[r-(1<<lg)+1][lg]));
28     }
29     return 0;
30 }

 

posted @ 2018-12-08 20:22  浅夜_MISAKI  阅读(294)  评论(1编辑  收藏  举报