zoukankan      html  css  js  c++  java
  • 回文自动机刷题总结

    最长双回文串

    裸的回文自动机,将串reverse再插入一遍即可。

    双倍回文

    这题可以只维护偶回文串然后疯狂加特判判掉奇串

    回文自动机,再多维护一个trans指针,指向trans[x]表示长度小于len[x]/2的最长的回文后缀

    trans指针可以从父亲(不是fail)的trans指针求出。

    其实还可以直接建完自动机后在fail树(即把fail指针当作父亲边构成的树)上开桶dfs

     1 #include<bits/stdc++.h>
     2 #define N 500050
     3 using namespace std;
     4 int n;
     5 char s[N];
     6 struct PAM{
     7     int tot,las;
     8     struct node{int len,fail,trans,ch[26];}tr[N];
     9     PAM(){tr[0].fail=-1;}
    10     inline int extend(int n){
    11         int c=s[n]-'a',p=las;
    12     //    cout<<tr[p].len<<endl;
    13         while((~p)&&s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
    14     //    cout<<n<<"-> "<<p<<endl;
    15         if(p==-1){las=0;return 0;}
    16         if(!tr[p].ch[c]){
    17             int np=++tot,k=tr[p].fail;
    18             tr[np].len=tr[p].len+2;
    19             while((~k)&&s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
    20             if(~k){
    21                 tr[np].fail=tr[k].ch[c];
    22                 if(tr[np].len>2){
    23                     k=tr[p].trans;
    24                     while((~k)&&(s[n-tr[k].len-1]!=s[n]||tr[k].len+2>(tr[np].len>>1)))
    25                         k=tr[k].fail;
    26         //            cout<<np<<" "<<k<<endl;
    27                     if(~k)tr[np].trans=tr[k].ch[c];
    28                 }
    29             }tr[p].ch[c]=np;
    30         }
    31         las=tr[p].ch[c];
    32     //    cout<<n<<" "<<las<<" "<<tr[las].len<<" "<<tr[las].trans<<" "<<tr[tr[las].trans].len<<endl;
    33         return tr[tr[las].trans].len==(tr[las].len>>1)?tr[las].len:0;
    34     }
    35 }t1;
    36 int main(){
    37     scanf("%d%s",&n,s+1);
    38     int ans=0;
    39     for(int i=1,x;i<=n;++i)
    40         x=t1.extend(i),ans=max(ans,x);
    41     cout<<ans<<endl;
    42     return 0;
    43 }
    View Code

    Antisymmetry

    题意转化一下,可以用回文自动机。

    在插入一个点后,立马把它取反,然后自动机正常建即可。

    额,好像不能正常建,只建偶回文串

    然后倒扫一遍自动机的节点统计答案,并累加贡献即可。

     1 #include<bits/stdc++.h>
     2 #define N 500050
     3 #define int long long
     4 using namespace std;
     5 int n;
     6 char s[N];
     7 struct PAM{
     8     int las,tot;
     9     struct node{
    10         int len,sz,fail,ch[2];
    11     }tr[N];
    12     PAM(){tr[0].fail=-1;}
    13     inline void extend(int n){
    14         int p=las,c=s[n]-'0';
    15         while((~p)&&s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
    16         if(!(~p)){las=0;return;}
    17 //        printf("%d %d
    ",n,p);
    18         if(!tr[p].ch[c]){
    19             int np=++tot,k=tr[p].fail;
    20             tr[np].len=tr[p].len+2;
    21             while((~k)&&s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
    22             if(k!=-1)tr[np].fail=tr[k].ch[c];
    23             tr[p].ch[c]=np;
    24         }
    25         las=tr[p].ch[c];++tr[las].sz;
    26 //        printf("las:%d len:%d fail:%d
    ",las,tr[las].len,tr[las].fail);
    27     }
    28     inline int getans(){
    29         int ret=0;
    30 //        cout<<tot<<endl;
    31         for(int i=tot;i;--i){
    32 //            printf("i:%d len:%d sz:%d
    ",i,tr[i].len,tr[i].sz);
    33             if(!(tr[i].len&1))ret+=tr[i].sz;
    34             tr[tr[i].fail].sz+=tr[i].sz;
    35         }
    36         return ret;
    37     }
    38 }t1;
    39  main(){
    40     scanf("%lld%s",&n,s+1);
    41     for(int i=1;i<=n;++i){
    42         t1.extend(i);
    43         s[i]=s[i]=='0'?'1':'0';
    44     }
    45 //    printf("%s
    ",s+1);
    46     printf("%lld
    ",t1.getans());
    47     return 0;
    48 }
    View Code

    I Love Palindrome String

    和双倍回文类似。在最后的fail树上开桶dfs统计答案,在回溯时累加贡献。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define N 300050
     6 using namespace std;
     7 int n;char s[N];
     8 int ans[N],t[N];
     9 struct PAM{
    10     int las,tot;
    11     int he[N],ne[N<<1],to[N<<1],bk[N],cnt,ans[N];
    12     struct node{
    13         int ch[26],sz,len,fail;
    14         inline void clear(){
    15             memset(ch,0,sizeof(ch));
    16             sz=len=fail=0;
    17         }
    18     }tr[N];
    19     inline void add(int x,int y){
    20         to[++cnt]=y;ne[cnt]=he[x];he[x]=cnt;
    21     }
    22     inline void init(){
    23         memset(he,0,sizeof(int)*(n+1));
    24         memset(ans,0,sizeof(int)*(n+1));
    25         cnt=tot=las=0;
    26         tr[0].clear();tr[1].clear();
    27         tr[tot=1].len=-1;tr[0].fail=1;
    28         add(1,0);
    29     }
    30     inline void extend(int n){
    31         int c=s[n]-'a',p=las;
    32         while(s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
    33         if(!tr[p].ch[c]){
    34             int np=++tot,k=tr[p].fail;tr[np].clear();
    35             tr[np].len=tr[p].len+2;
    36             while(s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
    37             tr[np].fail=tr[k].ch[c];
    38             add(tr[k].ch[c],np);
    39             tr[p].ch[c]=np;
    40         }
    41         las=tr[p].ch[c];++tr[las].sz;
    42     //    printf("n:%d las:%d len:%d sz:%d fail:%d
    ",n,las,tr[las].len,tr[las].sz,tr[las].fail);
    43     }
    44     inline void dfs(int g){
    45     //    printf("g:%d sz:%d len:%d fail:%d
    ",g,tr[g].sz,tr[g].len,tr[g].fail);
    46         if(tr[g].len>0)++bk[tr[g].len];
    47         for(int i=he[g];i;i=ne[i]){
    48             dfs(to[i]);
    49             tr[g].sz+=tr[to[i]].sz;
    50         }
    51         if(bk[tr[g].len+1>>1]&&tr[g].len>0)ans[tr[g].len]+=tr[g].sz;
    52         if(tr[g].len>0)--bk[tr[g].len];
    53     }
    54     inline void pr(){
    55         for(int i=1;i<n;++i)printf("%d ",ans[i]);
    56         printf("%d
    ",ans[n]);
    57     }
    58 }t1;
    59 int main(){
    60     if(scanf("%s",s+1)==EOF)return 0;
    61     t1.init();n=strlen(s+1);
    62     for(int i=1;i<=n;++i)t1.extend(i);
    63     t1.dfs(1);
    64     t1.pr();
    65     return main();
    66 }
    View Code

    对称的正方形

    这题正解不是回文自动机,出这题的时候回文自动机还没怀上呢。。

    二分加二维hash

     1 #include<bits/stdc++.h>
     2 #define N 1010
     3 #define ull unsigned long long
     4 using namespace std;
     5 inline int read(){
     6     int s=0;char c=getchar();
     7     while(c>'9'||c<'0')c=getchar();
     8     while(c>='0'&&c<='9')s=s*10+c-'0',c=getchar();
     9     return s;
    10 }
    11 int n,m,ans;
    12 ull a[N][N];
    13 const ull P1=1000000007,P2=13331;
    14 ull po1[N],po2[N];
    15 inline void to(int &t1,int &t2,int tag){
    16     if(tag&1)t1=n-t1+1;
    17     if(tag&2)t2=m-t2+1;
    18 }
    19 inline void init(int n){
    20     po1[0]=po2[0]=1;
    21     for(int i=1;i<=n;++i)po1[i]=po1[i-1]*P1,po2[i]=po2[i-1]*P2;
    22 }
    23 struct HASH{
    24     ull ha[N][N],now;
    25     inline void init(int tag){
    26         for(int i=1;i<=n;++i){
    27             for(int j=1,x,y;j<=m;++j){
    28                 x=i,y=j;
    29                 to(x,y,tag);
    30                 ha[i][j]=ha[i-1][j]*P1+(ha[i][j-1]-ha[i-1][j-1]*P1)*P2+a[x][y];
    31             }
    32         }
    33     }
    34     inline void check(int x,int y,int len,int tag){
    35         to(x,y,tag);
    36         now=ha[x][y]
    37             -ha[x-len][y]*po1[len]
    38             -ha[x][y-len]*po2[len]
    39             +ha[x-len][y-len]*po1[len]*po2[len];
    40     }
    41 }H[4];
    42 int main(){
    43     scanf("%d%d",&n,&m);
    44     for(int i=1;i<=n;++i)
    45         for(int j=1;j<=m;++j)
    46             a[i][j]=read();
    47     init(max(n,m));
    48     for(int i=0;i<=3;++i)H[i].init(i);
    49     for(int i=1;i<=n;++i){
    50         for(int j=1,l,r;j<=m;++j){
    51             r=min(j,m-j);r=min(r,i);r=min(r,n-i);++r;l=0;
    52         //    printf("%d %d %d %d
    ",i,j,l,r);
    53             while(l+1<r){
    54                 int mid=l+r>>1;
    55                 H[0].check(i,j,mid,0);
    56                 H[1].check(i+1,j,mid,1);
    57                 H[2].check(i,j+1,mid,2);
    58                 H[3].check(i+1,j+1,mid,3);
    59                 if(H[0].now==H[1].now&&H[1].now==H[2].now&&H[2].now==H[3].now)l=mid;
    60                 else r=mid;
    61         //        if(i==1&&j==3)
    62         //        printf("%llu %llu %llu %llu
    ",H[0].now,H[1].now,H[2].now,H[3].now);
    63             }
    64             ans+=l;
    65             r=min(j,m-j+1);r=min(r,i);r=min(r,n-i+1);l=1;++r;
    66             while(l+1<r){
    67                 int mid=l+r>>1;
    68                 H[0].check(i,j,mid,0);
    69                 H[1].check(i,j,mid,1);
    70                 H[2].check(i,j,mid,2);
    71                 H[3].check(i,j,mid,3);
    72                 if(H[0].now==H[1].now&&H[1].now==H[2].now&&H[2].now==H[3].now)l=mid;
    73                 else r=mid;
    74             }
    75             ans+=l;
    76         }
    77     }
    78     cout<<ans<<endl;
    79     return 0;
    80 }
    View Code
  • 相关阅读:
    第五周学习进度条
    课堂实验4.1(环数组)
    每日站立会议(3)
    每日站立会议(2)
    找水王
    购买一批书的最低价格
    每日站立会议(1)
    NABCD分析
    团队开发博客
    返回一个二维整数数组中的最大子数组之和(环)
  • 原文地址:https://www.cnblogs.com/loadingkkk/p/12098461.html
Copyright © 2011-2022 走看看