codeforces #30E Tricky and Clever Password KMP+Manacher+二分

来源:互联网 发布:前端开发算程序员吗 编辑:程序博客网 时间:2024/06/05 23:56

题目大意:给定一个字符串S,要求分成A+prefix+B+middle+C+suffix6段,满足:
|prefix|=|suffix|
|middle|为奇数
prefix+middle+suffix为回文串
middle外所有段长度都可以为0
要求最大化|prefix|+|middle|+|suffix|,输出一组方案(|prefix|=|suffix|=0时只输出middle)

首先我们发现suffix串是顶着右端点的,因此我们可以枚举|suffix|
对于每个|suffix|我们需要求出最左侧能与suffix匹配的prefix
我们发现随着|suffix|的增大,prefix的位置是单调不减的,因此我们可以用KMP算法求出对于每个|suffix|最靠左的prefix
现在对于一个确定的prefix串和suffix串,我们需要求出中间的区间内最长的回文子串middle

现在就是区间最长回文子串的问题了

一种做法是这样的:
首先利用Manacher算法求出以每个点为中心的最长回文半径,然后对于每次询问我们二分答案:
设询问区间为[L,R],二分长度为M,那么如果[L+M1,RM+1]区间最大的最长回文半径M则存在回文半径为M的回文子串,否则不存在
利用ST表即可做到单次询问O(logn)

我还YY出了一种SB做法:
观察这个题的所有询问,我们发现询问区间是依次包含的
因此我们可以从最小的区间开始依次拓展
每次拓展,假设当前拓展的是R,那么我们需要用以R结尾,长度不超过RL+1的最长回文子串来更新答案
这个用回文自动机+树上倍增就可以了

= =所以说是傻逼做法嘛

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100#define MOD 999911657#define BASE 2333using namespace std;int n,ans;char s[M],rev_s[M];int next[M],f[M],pos[M];pair<int,int> intervals[M];int log_2[M],a[M][17],_ans[M];void KMP(){    int i,fix=0;    for(i=2;i<=n;i++)    {        while( fix && rev_s[fix+1]!=rev_s[i] )            fix=next[fix];        if( rev_s[fix+1]==rev_s[i] )            ++fix;        next[i]=fix;    }    fix=0;    for(i=1;i<=n;i++)    {        while( fix && rev_s[fix+1]!=s[i] )            fix=next[fix];        if( rev_s[fix+1]==s[i] )            ++fix;        if( i+fix>=n )            return ;        if(!pos[fix])        {            pos[fix]=i;            intervals[fix]=make_pair(i+1,n-fix);        }    }}void Manacher(){    int i,id=1,mx=1;    s[0]='$';    for(i=1;i<=n;i++)    {        f[i]=min(mx-i+1,f[id+id-i]);        while(s[i+f[i]]==s[i-f[i]])            ++f[i];        if(i+f[i]-1>mx)            mx=i+f[i]-1,id=i;    }}int Get_Max(int x,int y){    int len=log_2[y-x+1];    return max(a[x][len],a[y-(1<<len)+1][len]);}int Bisection(int x,int y){    int l=1,r=y-x+2>>1;    while(l+1<r)    {        int mid=l+r>>1;        if( Get_Max(x+mid-1,y-mid+1)>=mid )            l=mid;        else            r=mid;    }    return Get_Max(x+r-1,y-r+1)>=r?r:l;}int main(){    int i,j;    scanf("%s",s+1);n=strlen(s+1);    for(i=1;i<=n;i++)        rev_s[i]=s[n-i+1];    KMP();    Manacher();    pos[0]=1;intervals[0]=make_pair(1,n);    for(i=2;i<=n;i++)        log_2[i]=log_2[i>>1]+1;    for(i=1;i<=n;i++)        a[i][0]=f[i];    for(j=1;j<=log_2[n];j++)        for(i=1;i+(1<<j)-1<=n;i++)            a[i][j]=max(a[i][j-1],a[i+(1<<j-1)][j-1]);    for(i=0;pos[i];i++)    {        _ans[i]=2*Bisection(intervals[i].first,intervals[i].second)-1;        if(i*2+_ans[i]>ans*2+_ans[ans])            ans=i;    }    if(ans==0)    {        cout<<1<<endl;        for(i=1;i<=n;i++)            if(f[i]*2-1==_ans[0])            {                cout<<i-f[i]+1<<' '<<_ans[0]<<endl;                return 0;            }    }    else    {        cout<<3<<endl;        cout<<pos[ans]-ans+1<<' '<<ans<<endl;        int l=intervals[ans].first,r=intervals[ans].second;        for(i=l;i<=r;i++)            if( min(min(i-l,r-i)+1,f[i])*2-1==_ans[ans] )            {                cout<<i-(_ans[ans]>>1)<<' '<<_ans[ans]<<endl;                break;            }        cout<<n-ans+1<<' '<<ans<<endl;    }    return 0;}
2 0