bzoj3676:回文串(manacher+SAM的parent树上倍增)

来源:互联网 发布:element linux 编辑:程序博客网 时间:2024/05/29 17:41

模拟考是碰到的,以前听过但没有做过,当场推出来了。
题面
题意就是给你一个串,定义字串的得分为长度*出现次数,问所有回文串中的最大得分。
题目分析:回文串当然首推manacher算法,只有当右指针右移时才会出现本质不同的回文串,得到该串的l和r,然后就是统计该串出现次数,很水的的我只会SAM了。
SAM的每个状态的所有串互为后缀,还记下了Right集,大小即为这个状态所有串的出现次数,还有Min和Max,表示这些串的长度范围,Min=Max(pre)+1。
先找到插入第r个字符时的状态,然后以Max为二分依据在parent树上倍增,找到字串[l,r]所属的状态,并统计答案。

#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))typedef long long LL;const int N=300300,mo=1e9+7;char s[N],ss[2*N];int n;int last=1,cur=1;int pos[N],dep[2*N],pre[2*N],son[2*N][26],fa[2*N][20],siz[2*N];int bl[N*2];LL ans;struct yy{    int num,de;}f[N*2];bool cmp(yy x,yy y){    return x.de<y.de;}void insert(int x,int id){    dep[++cur]=dep[last]+1;    int np=cur,p=last;    last=cur;    pos[id]=cur;    siz[cur]=1;    for(;!son[p][x];p=pre[p])    son[p][x]=np;    if(!p)    pre[np]=1;    else    {        int q=son[p][x];        if(dep[q]==dep[p]+1)        pre[np]=q;        else        {            dep[++cur]=dep[p]+1;            int nq=cur;            pre[nq]=pre[q];            pre[q]=pre[np]=nq;            mmcp(son[nq],son[q]);            for(;son[p][x]==q;p=pre[p])            son[p][x]=nq;        }    }}void query(int l,int r){    if(l%2==0||r%2==0)    return;    l=(l+1)/2;    r=(r+1)/2;    int mid=pos[r];    for(int j=18;j>=0;j--)    {        int t=fa[mid][j];        if(dep[t]>=r-l+1)        mid=t;    }    ans=max(ans,1ll*(r-l+1)*siz[mid]);}void manacher(){    int ret=0,mx=0,id=0;    bl[0]=1;    for(int i=0;i<=n;i++)    ss[i*2]='&';    for(int i=0;i<n;i++)    ss[i*2+1]=s[i];    ss[2*n]='!';    for(int i=1;i<n*2+1;i++)    {        if(mx>i)        bl[i]=min(bl[2*id-i],mx-i);        else {            bl[i]=1;            query(i,i);        }        while(ss[i-bl[i]]==ss[i+bl[i]])        {            query(i-bl[i],i+bl[i]);            bl[i]++;        }        if(mx<=bl[i]+i)        mx=bl[i]+i-1,id=i;    }}int main(){    freopen("2115.in", "r", stdin);    freopen("2115.out", "w", stdout);    scanf("%s",s);    n=strlen(s);    for(int i=0;i<n;i++)    insert(s[i]-'a',i+1);    for(int i=1;i<=cur;i++)    fa[i][0]=pre[i];    fa[1][0]=1;    for(int j=1;j<=18;j++)    for(int i=1;i<=n;i++)    fa[i][j]=fa[fa[i][j-1]][j-1];    for(int i=1;i<=cur;i++)    {        f[i].num=i;        f[i].de=dep[i];    }    sort(f+1,f+cur+1,cmp);    for(int i=cur;i>=1;i--)    {        int hy=f[i].num;        siz[pre[hy]]+=siz[hy];    }    manacher();    cout<<ans<<endl;    return 0;}
阅读全文
1 0