1. 程式人生 > >HDU 5421 Victor and String (迴文自動機)

HDU 5421 Victor and String (迴文自動機)

題目大意:讓你維護一個字串,支援在開頭結尾插入字元,以及查詢本質不同的迴文串數量以及迴文串總數量

開頭結尾都維護一個$last$指標,如果插入新字元後,整個串是一個迴文串,就把另一個$last$賦值成當前的$last$

為什麼這樣做就是正確的呢?

首先,對於這道題而言,一個迴文串開頭/結尾是等價的

不合並$last$的情況下,在當前方向新增字元不會被另一個方向所影響,就相當於只在末尾加字元

如果合併了$last$,說明現在另一個方向的開頭字元,能和新新增的字元共同產生貢獻,所以必須把另一個$last$賦值成當前的$last$,來完成都是在末尾新新增字元的“假象”

本質不同的迴文串數量就是節點個數,迴文串總數量就是所有節點在$pre$樹中的深度總和*作為迴文末尾的次數

每次$insert$時都更新即可,注意開$longlong$

  1 #include <cmath>
  2 #include <vector>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define N1 200100
  7 #define S1 (N1<<1)
  8 #define ll long long
  9 #define uint unsigned int
 10 #define
rint register int 11 #define dd double 12 #define il inline 13 #define inf 0x3f3f3f3f 14 #define idx(X) (X-'a') 15 using namespace std; 16 17 int gint() 18 { 19 int ret=0,fh=1;char c=getchar(); 20 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 21 while(c>='
0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 22 return ret*fh; 23 } 24 int n,L,R; 25 namespace PAM{ 26 int trs[N1][26],pre[N1],dep[N1],num[N1]; 27 int lla,rla,tot;ll sum; 28 void init(){tot=lla=rla=1,dep[1]=-1,pre[0]=pre[1]=1;} 29 int lchk(char *str,int i,int p){return str[i+dep[p]+1]!=str[i]?1:0;} 30 int rchk(char *str,int i,int p){return str[i-dep[p]-1]!=str[i]?1:0;} 31 void Lins(char *str,int i) 32 { 33 int p=lla,np,fp,c=idx(str[i]); 34 while(lchk(str,i,p)) p=pre[p]; 35 if(!trs[p][c]) 36 { 37 np=++tot; 38 dep[np]=dep[p]+2; 39 fp=pre[p]; 40 while(lchk(str,i,fp)) fp=pre[fp]; 41 pre[np]=trs[fp][c]; 42 trs[p][c]=np; 43 num[np]=num[pre[np]]+1; 44 } 45 lla=trs[p][c]; 46 if(dep[trs[p][c]]==R-L+1) rla=lla; 47 sum+=num[lla]; 48 } 49 void Rins(char *str,int i) 50 { 51 int p=rla,np,fp,c=idx(str[i]); 52 while(rchk(str,i,p)) p=pre[p]; 53 if(!trs[p][c]) 54 { 55 np=++tot; 56 dep[np]=dep[p]+2; 57 fp=pre[p]; 58 while(rchk(str,i,fp)) fp=pre[fp]; 59 pre[np]=trs[fp][c]; 60 trs[p][c]=np; 61 num[np]=num[pre[np]]+1; 62 } 63 rla=trs[p][c]; 64 if(dep[trs[p][c]]==R-L+1) lla=rla; 65 sum+=num[rla]; 66 } 67 void clr() 68 { 69 tot++; 70 memset(trs,0,tot*4*26); 71 memset(pre,0,tot*4); 72 memset(dep,0,tot*4); 73 memset(num,0,tot*4); 74 tot=lla=rla=0;sum=0; 75 } 76 }; 77 char str[N1]; 78 79 int main() 80 { 81 //freopen("t2.in","r",stdin); 82 //freopen("a.out","w",stdout); 83 while(scanf("%d",&n)!=EOF) 84 { 85 int fl;L=100001,R=100000; 86 char tmp[10]; 87 PAM::clr(),PAM::init(); 88 memset(str,0,sizeof(str)); 89 while(n--) 90 { 91 scanf("%d",&fl); 92 if(fl==1){ 93 scanf("%s",tmp); 94 str[--L]=tmp[0]; 95 PAM::Lins(str,L); 96 }else if(fl==2){ 97 scanf("%s",tmp); 98 str[++R]=tmp[0]; 99 PAM::Rins(str,R); 100 }else if(fl==3){ 101 printf("%d\n",PAM::tot-1); 102 }else if(fl==4){ 103 printf("%lld\n",PAM::sum); 104 } 105 } 106 } 107 return 0; 108 }