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 }

 

posted @ 2018-12-18 20:31  guapisolo  阅读(248)  评论(0编辑  收藏  举报