1. 程式人生 > 實用技巧 >HDU-5421 Victor and String 迴文自動機

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;
}