HDU-5421 Victor and String 迴文自動機
阿新 • • 發佈:2020-11-23
HDU-5421 Victor and String
題意
給定一個空串\(S\),有\(n\)次操作,操作有如下四種:
- \(1~c\),在\(S\)前增加一個字元\(c\)。
- \(2~c\),在\(S\)後增加一個字元\(c\)。
- \(3\),輸出\(S\)中本質不同的迴文子串個數。
- \(4\),輸出\(S\)中不同的迴文子串個數,位置不同的子串算多個。
\(n\le 10^5\)
分析
迴文自動機額外記錄一個前端插入的last即可,前端插入和後端插入操作是類似的,唯一和之前不同的地方是當\(last\)是整個串時,要更新另外一端的\(last\)為當前這一端的\(last\)。
Code
#include<bits/stdc++.h> #define fi first #define se second #define pb push_back #define lson l,mid,p<<1 #define rson mid+1,r,p<<1|1 #define ll long long using namespace std; const int inf=1e9; const int mod=1e9+7; const int maxn=5e5+10; char s[maxn]; int n,now,l,r; ll ans; struct PAM{ int son[maxn][26],fail[maxn],len[maxn],cnt[maxn],tot,suf,pre,last; int newnode(int x){ ++tot; for(int i=0;i<26;i++) son[tot][i]=0; fail[tot]=0;len[tot]=x; return tot; } void init(){ tot=-1;newnode(0);newnode(-1); fail[0]=1; suf=pre=0; l=1e5+5,r=l-1; } int gao(int x,int op){ while(s[now+op*len[x]+op]!=s[now]) x=fail[x]; return x; } void insert(int op){ int last=op==1?pre:suf; int p=gao(last,op); if(!son[p][s[now]-'a']){ int tmp=son[gao(fail[p],op)][s[now]-'a']; son[p][s[now]-'a']=newnode(len[p]+2); fail[tot]=tmp; cnt[tot]=cnt[tmp]+1; } last=son[p][s[now]-'a']; ans+=cnt[last]; if(op==1) pre=last; else suf=last; if(len[last]==r-l+1) suf=pre=last; } int qy(){ return len[last]; } }P; int main(){ while(~scanf("%d",&n)){ memset(s,0,sizeof(s)); P.init(); ans=0; while(n--){ int op; char c; scanf("%d",&op); if(op==1){ scanf(" %c",&c); s[--l]=c; now=l; P.insert(1); }else if(op==2){ scanf(" %c",&c); s[++r]=c; now=r; P.insert(-1); }else if(op==3){ printf("%d\n",P.tot-1); }else{ printf("%lld\n",ans); } } } return 0; }