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 }