As Easy As Possible 倍增法

来源:互联网 发布:卖汉服的淘宝店 编辑:程序博客网 时间:2024/05/16 05:16
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

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;}


原创粉丝点击