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
  • 相关阅读:
    POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)
    UVaLive 5031 Graph and Queries (Treap)
    Uva 11996 Jewel Magic (Splay)
    HYSBZ
    POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)
    HDU 1890 Robotic Sort (Splay 区间翻转)
    【转】ACM中java的使用
    HDU 4267 A Simple Problem with Integers (树状数组)
    POJ 1195 Mobile phones (二维树状数组)
    HDU 4417 Super Mario (树状数组/线段树)
  • 原文地址:https://www.cnblogs.com/loadingkkk/p/12098461.html
Copyright © 2011-2022 走看看