1 条题解

  • 0
    @ 2025-10-8 16:59:21

    推荐去看学习资料
    友情赞助参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    const int MAXN=310000;
    char S[MAXN];int slen;
    struct PAM
    {
    	int len[MAXN],fail[MAXN],son[MAXN][26],p,n,last;
    	//p:当前节点个数(p-2就是回文子串种类)  n:字符串我们匹配了多少 last:第n个点弄进来之前的最长回文后缀节点位置 
    	inline int newpoint(int l)//创建新的点,长度为l ,并返回节点编号 
    	{
    		for(int i=0;i<=25;i++)son[p][i]=0;
    		len[p]=l;
    		return p++;
    	}
    	inline void putin()//初始化:建立节点even,odd
    	{
    		n=p=last=0;
    		newpoint(0);
    		newpoint(-1);
    		fail[0]=1;S[0]=-1;//我们弄一个不可能出现在字符域的字符,避免翻车 (我们fail要经过0才能跑到1) 
    	}
    	int get_fail(int x)
    	{
    		while(S[n]!=S[n-1-len[x]])x=fail[x];
    		return x;
    	}
    	inline void add(int c)
    	{
    		c-='a';S[++n]=c;
    		int FA=get_fail(last);
    		if(son[FA][c]==0)//这里不等于0我们找到的就是一个以前出现过的子串 
    		{
    			int now=newpoint(len[FA]+2);//前后都加一个'c',所以我们长度是+2
    			fail[now]=son[get_fail(fail[FA])][c]; //这里求fail类似于AC自动机,找到父亲的fail(们)的儿子'c' 
    			son[FA][c]=now;
    		}
    		last=son[FA][c];//现在的最长回文后缀就是last了 
    	}
    }pam;
    int main()
    {
    //	freopen("data10.in","r",stdin);
    //	freopen("data10.out","w",stdout);
    	scanf("%s",S+1);slen=strlen(S+1);
    	pam.putin();
    	for(int i=1;i<=slen;i++)pam.add(S[i]);
    	printf("%d\n",pam.p-2);
    	return 0;
    }
    
    • 1

    回文自动机(回文树,PAM)模板

    信息

    ID
    1944
    时间
    1000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    19
    已通过
    5
    上传者