As we know, the NTU Final PK contest usually tends to be pretty hard. Many teams got frustrated when participating NTU Final PK contest. So I decide to make the first problem as “easy” as possible. But how to know how easy is a problem? To make our life easier, we just consider how easy is a string.
Here, we introduce a sane definition of “easiness”. The easiness of a string is the maximum times of “easy” as a subsequence of it. For example, the easiness of “eeaseyaesasyy” is 2. Since “easyeasy” is a subsequence of it, but “easyeasyeasy” is too easy.
How to calculate easiness seems to be very easy. So here is a string s consists of only ‘e’, ‘a’, ‘s’, and ‘y’. Please answer m queries. The i-th query is a interval [li , ri ], and please calculate the easiness of s[li ..ri ].
Input
The first line contains a string s. The second line contains an integer m. Each of following m lines contains two integers li
, ri .
• 1 ≤ |s| ≤ 105
• 1 ≤ m ≤ 105
• 1 ≤ li ≤ ri ≤ |s|
• s consists of only ‘e’, ‘a’, ‘s’, and ‘y’
Output
For each query, please output the easiness of that substring in one line.
Sample input 1
easy
3
1 4
2 4
1 3
Sample output 1
1
0
0
Sample input 2
eeaseyaesasyy
4
1 13
2 12
2 10
3 11
Sample output 2
2
2
1
Here, we introduce a sane definition of “easiness”. The easiness of a string is the maximum times of “easy” as a subsequence of it. For example, the easiness of “eeaseyaesasyy” is 2. Since “easyeasy” is a subsequence of it, but “easyeasyeasy” is too easy.
How to calculate easiness seems to be very easy. So here is a string s consists of only ‘e’, ‘a’, ‘s’, and ‘y’. Please answer m queries. The i-th query is a interval [li , ri ], and please calculate the easiness of s[li ..ri ].
Input
The first line contains a string s. The second line contains an integer m. Each of following m lines contains two integers li
, ri .
• 1 ≤ |s| ≤ 105
• 1 ≤ m ≤ 105
• 1 ≤ li ≤ ri ≤ |s|
• s consists of only ‘e’, ‘a’, ‘s’, and ‘y’
Output
For each query, please output the easiness of that substring in one line.
Sample input 1
easy
3
1 4
2 4
1 3
Sample output 1
1
0
0
Sample input 2
eeaseyaesasyy
4
1 13
2 12
2 10
3 11
Sample output 2
2
2
1
0
题意:给出一个只含有'e' ,'a','s' ,'y' 四种字符的字符串,询问m次区间[ Li, Ri ]的子序列中形如easyeasy的字符串最多重复easy多少次。
我的做法是对于每一个位置先倒序处理一遍得到每一个'e'后面的第一个'a'的位置,每一个'a'后面的第一个's'的位置等等,还有每个字符后第一个'e'的位置,
再求出每个字符沿着'e','a','s','y'的循环往后走2^n步会到达的位置,然后先在给定区间内找到第一个'e'的位置再用倍增法往后移动统计走过了多少个easy,直到往后走4步就会越界,就暴力往后走3步看会不会越界,如果不会越界则统计数加1。
因为用倍增法走2^n(n>2)步后所在的位置的字符还是'e',所以可以直接统计出答案。
时间复杂度:O(nlogn)
队友的做法是分块,每一个块储存有多少个'easy'子序列,每个块第一个'easy'的子序列前一段是有否有'y','sy','asy'这样的子序列,每个块的最后一个'easy'子序列后是否有'e','ea','eas'这样的子序列,这样就可以完成块与块之间的转移。时间复杂度O(n*sqrt(n)),时限1s,也可以过这题。
我的代码:
#include <bits/stdc++.h>
using namespace std;
inline void read(int &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void write(int x){
static const int maxlen=100;
static char s[maxlen];
if (x<0) { putchar('-'); x=-x;}
if(!x){ putchar('0'); return; }
int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
for(int i=len-1;i>=0;--i) putchar(s[i]);
}
inline void write(long long x){
static const int maxlen=100;
static char s[maxlen];
if (x<0) { putchar('-'); x=-x;}
if(!x){ putchar('0'); return; }
int len=0; for(;x;x/=10) s[len++]=x % 10+'0';
for(int i=len-1;i>=0;--i) putchar(s[i]);
}
const int maxn=120000;
char s[maxn];
int nex[maxn][22];
int st[maxn];
int now[22];
int a[maxn];
int n;
int get_num( char ch){
if (ch=='e')
return 0;
if (ch=='a')
return 1;
if (ch=='s')
return 2;
if (ch=='y');
return 3;
}
void doit(int l,int r){
int x=l;
int nowlen=20;
int ans=0;
x=st[ l ];
if ( (x>r)|| (x==0) )
{
puts("0");
return ;
}
for (;;)
{
while ( ( nowlen>0 ) && ( ( ( nex[x][nowlen]==0 ) || ( nex[x][nowlen]>r ) ) ) )
nowlen--;
if ( nowlen < 2 )
break;
ans+=( 1<<( nowlen-2 ) );
x=nex[x][nowlen];
}
int cnt=0;
while ( (nex[x][0]<=r)&& (nex[x][0]!=0) )
{
x=nex[x][0];
cnt++;
}
if (cnt==3)
ans++;
printf("%d\n",ans);
}
int main(){
scanf("%s",s);
n=strlen(s);
for (int i=0;i<n;i++)
a[i+1]=get_num( s[i]);
for (int i=n;i>=1;i--)
{
nex[i][0]=now[ (a[i]+1)%4 ];
now[ a[i] ]=i;
st[ i ]=now[0];
}
for (int i=1;i<=20;i++)
for (int j=1;j<=n;j++)
nex[ j ][ i ]=nex[ nex[ j ][ i-1] ] [ i-1 ];
int m;
read(m);
for (int i=1;i<=m;i++)
{
int l,r;
read(l); read(r);
int tot=0;
doit( l , r);
}
return 0;
}