HDU-5421 Victor and String 回文自动机
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;
}