[Hdu5421]Victor and String

题意

动态在串的前后插入字符,问当前本质不同的回文串个数,和所有回文串个数


题解

如果只有后端插入,那么就是回文自动机的模板

考虑前端插入的影响

我们在后端插入时,一直维护着最长回文后缀,那么在前端插入的时候,很自然想到维护最长回文前缀,事实上确实是这样做的

跟后端插入一样,我们考虑维护一个 fail' f a i l ′ 表示一个串的最长回文前缀.那么每次前端插入就沿着 fail' f a i l ′ 跑就好了

然而事实上,对于一个点 t t 而言,由于t是回文串, t t 的每一个回文后缀t=t[i|t|]的翻转,都和 t t 的回文前缀t=t[1|t|i+1]相等,而 t t ′ t′′ t ″ 本身又是回文串,那么 t=t′′ t ′ = t ″ 所以 fail f a i l ′ 实际上就是 fail f a i l

那么,我们只用考虑维护当前最长回文前缀和后缀就好了

注意在前(后)端插入时,不仅会改变对最长回文前(后)缀,还有可能对最长回文后(前)缀造成影响,而这个情况很明显,就是整个串是回文串的时候

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5;
typedef int arr[N];
typedef long long ll;
int m;char s[N];
struct node{
    int ch[26],fail,len;
    inline void New(int a,int b){
        memset(ch,0,sizeof ch);fail=a,len=b;
    }
};
struct PAM{
    int L,R,tot,las[2];arr s,dep;node a[N];ll sum;
    inline void init(int n){
        L=n,R=n-1,memset(s,-1,sizeof s),tot=1;
        sum=las[0]=las[1]=0;a[0].New(1,0),a[1].New(0,-1);
    }
    inline int gf(int x,int d){
        if(d)while(s[R-a[x].len-1]^s[R])x=a[x].fail;
        else while(s[L+a[x].len+1]^s[L])x=a[x].fail;
        return x;
    }
    inline void ins(int v,int d){
        d?s[++R]=v:s[--L]=v;
        int&u=tot;las[d]=gf(las[d],d);
        if(!a[las[d]].ch[v]){
            a[++u].New(a[gf(a[las[d]].fail,d)].ch[v],a[las[d]].len+2);
            a[las[d]].ch[v]=u,dep[u]=dep[a[u].fail]+1;
        }las[d]=a[las[d]].ch[v];sum+=dep[las[d]];
        if(a[las[d]].len==R-L+1)las[d^1]=las[d];//最后一句所说的特判
    }
}p;
inline void sol(){
    int op;char c;p.init(m);
    while(m--){
        scanf("%d",&op);
        switch(op){
            case 1:case 2:
                scanf(" %c",&c);p.ins(c-'a',op-1);
            break;
            case 3:we(p.tot-1);break;
            case 4:we(p.sum);break;
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    while(~scanf("%d",&m))sol();
return Ot(),0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值