回文自动机刷题总结

最长双回文串

裸的回文自动机,将串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 }

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",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\n",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\n",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\n",s+1);
46     printf("%lld\n",t1.getans());
47     return 0;
48 }

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",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\n",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\n",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 }

对称的正方形

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

二分加二维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\n",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\n",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 }

原文地址:https://www.cnblogs.com/loadingkkk/p/12098461.html

时间: 2024-08-29 21:02:57

回文自动机刷题总结的相关文章

回文自动机入门题

URAL-1960.Palindromes and Super Abilities 传送门 •题意 给你一个长度为 n 的字符串 s,下标从 1 开始: 输出 n 个数,第 i 个数表示 1~i 内有多少个本质不同的回文串: •题解 回文自动机入门题: 定义 ans[ i ] 表示 1~i 共有 $ans_{i}$ 个本质不同的回文串: $ans_{i}=ans_{i-1}$+{第 i 个字符可形成本质不同的回文串 ? 1:0}; •Code 1 #include<bits/stdc++.h>

【bzoj3676】[Apio2014]回文串 回文自动机

题目描述 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最大出现值. 输入 输入只有一行,为一个只包含小写字母(a -z)的非空字符串s. 输出 输出一个整数,为逝查回文子串的最大出现值. 样例输入 [样例输入l] abacaba [样例输入2] www 样例输出 [样例输出l] 7 [样例输出2] 4 题解 回文自动机裸题 关于PAM个人暂时理解不是很深入,挖坑待填. 本题只需要统计fail树的子树大小,再

hysbz3676 回文串 回文自动机

回文自动机模板题 头铁了一下午hdu6599,最后发现自己的板有问题 先放这里一个正确性得到基本确认的板,过两天肝hdu6599 #pragma GCC optimize(2) #include<bits/stdc++.h> #include<iostream> #include<cstring> #include<cassert> #define MAXN 300010 #define LL long long #define BASE 2LL #defi

P3649 [APIO2014]回文串(回文自动机)

回文自动机裸题,把PAM建出来以后对每个节点更新答案即可 代码: #include <bits/stdc++.h> #define int long long #define sc(a) scanf("%lld",&a) #define scc(a,b) scanf("%lld %lld",&a,&b) #define sccc(a,b,c) scanf("%lld %lld %lld",&a,&

[BZOJ4044]Virus synthesis 回文自动机的DP

4044: [Cerc2014] Virus synthesis Time Limit: 20 Sec  Memory Limit: 128 MB Description Viruses are usually bad for your health. How about fighting them with... other viruses? In this problem, you need to find out how to synthesize such good viruses. W

【XSY2715】回文串 树链剖分 回文自动机

题目描述 有一个字符串\(s\),长度为\(n\).有\(m\)个操作: \(addl ~c\):在\(s\)左边加上一个字符\(c\) \(addr~c\):在\(s\)右边加上一个字符 \(transl~l_1~r_1~l_2~r_2\):有两个\(s\)的子串\(s_1=s[l_1\ldots r_1],s_2=s[l_2\ldots r_2]\).你要把\(s_1\)变成\(s_2\).每次允许在左边加一个字符或删一个字符.要求操作次数最少.定义一个字符串是好的当且仅当这个字符串是回文串

「专题总结」回文自动机PAM

为了备课,把做完的专题的总结咕了这么久... 主要是自己做题做的太慢了,所以讲SAM的时候准备也不充分. 在把讲课时间不断咕之后依然是粗制滥造,锅很多,所以效果很差.而且还有人没听懂... 一半人都做了5道题以上了,另一半人还没怎么看,基本所有人都有预习. 得不到任何反馈,也不知道速度如何.就当凑活吧. 挺失败的.可能也没有下一次机会了. 我也不知道后缀数组推荐率是怎么达到100%的...那次我讲的自己也很满意 一到难的知识点我就不行了嘛...主要是自己理解也很不深刻 至少也还是在3个多小时之内

【回文自动机】bzoj3676 [Apio2014]回文串

回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i)代表个数(要最后在fail树上dp一遍方可). 答案直接枚举一遍结点,然后用len(i)*cnt(i),取最大者即可. 回文自动机是非常优越的数据结构,可惜比manacher多一个字符集的空间-- #include<cstdio> #include<cstring> #include

回文树或者回文自动机,及相关例题

回文树简述 在大部分说法中,回文树与回文自动机指的是一个东西: 回文树是对一个字符串,基于自动机思想构建的处理回文问题的树形结构: 回文树是对着一个单串建立的: 于是他主要用于计数(回文子串种类及个数) 基本建立思路是先建立其前缀的回文树,然后每加上一个字符,统计影响: 回文树存在fail指针但一般不承接字符串匹配问题: (回文树大概可以判定一个回文串是不是一个串的子串,但KMP之类的可以做得更好) 构建好的回文树,是这样的: (好难看) 可看出: 存在两个树结构,分别记录奇数|偶数长度的回文: