题解 P5555 【秩序魔咒】
为啥知道有回文自动机还要写带log的std啊
为啥放那么小范围放那么大时限啊
我记得我前几天刚刚放了PAM板子啊
前置芝士:回文自动机。不懂的可以去窝的模板那儿看看。
这个题问你最长公共回文子串长度和个数。
我们对两个字符串分别建回文自动机。回文自动机中的转移边形成了一个树形结构。
走相同的转移边,得到的回文串显然是相同的。
那么我们同时对两棵树进行dfs,每次都走相同的转移边,那么走到的每个节点代表的回文串一定是公共的。
这样就可以统计最长长度了。又由于回文自动机中每个节点代表的回文串不同,所以也可以同时统计出不同最长公共回文子串个数。
回文自动机的点数是
比std短,比std快,还比std好写。
Code:
#include<cstdio>
const int N=3e5+5;
char s[N],ss[N];
int mx=0,tot=0,n,m;
struct pam{
int len[N],fail[N],ch[N][26],tot,lst,num[N];
char s[N];
void init(char*ss){
tot=lst=1;
len[1]=-1,len[0]=0,fail[0]=1;
for(int i=1;ss[i];++i)s[i]=ss[i];
}
int insert(char cr,int ed){
int c=cr-'a';
int p=lst;
while(s[ed]!=s[ed-len[p]-1])
p=fail[p];
if(!ch[p][c]){
int np=++tot;
len[np]=len[p]+2;
int q;
for(q=fail[p];s[ed]!=s[ed-len[q]-1];q=fail[q]);
fail[np]=ch[q][c];
num[np]=num[fail[np]]+1;
ch[p][c]=np;
}
lst=ch[p][c];
return num[lst];
}
}p1,p2;
void dfs(int nl,int nr){
if(mx<p1.len[nl])mx=p1.len[nl],tot=1;else
if(mx==p1.len[nl])++tot;
for(int i=0;i<26;++i)
if(p1.ch[nl][i]&&p2.ch[nr][i])dfs(p1.ch[nl][i],p2.ch[nr][i]);
}
int main(){
scanf("%d%d",&n,&m);
scanf("%s%s",s+1,ss+1);
p1.init(s),p2.init(ss);
for(int i=1;s[i];++i)
p1.insert(s[i],i);
for(int i=1;ss[i];++i)
p2.insert(ss[i],i);
dfs(0,0);
dfs(1,1);
printf("%d %d\n",mx,tot);
return 0;
}