• 【BZOJ2342】双倍回文(回文树)


    【BZOJ2342】双倍回文(回文树)

    题面

    BZOJ

    题解

    构建出回文树之后
    (fail)树上进行(dp)
    如果一个点代表的回文串长度为(4)的倍数
    并且存在长度为它的一半的回文后缀
    那么就是可行的
    如何维护长度是一半的回文后缀?
    (fail)树上的父亲一定包括了它的所有的回文后缀
    因此在(fail)树上(dfs),同时记录一下每个长度的回文出现的次数
    这样访问到一个节点就可以直接检查了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 520000
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    int n,ans;
    char ch[MAX];
    struct Line{int v,next;}e[MAX];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    struct Palindromic_Tree
    {
    	struct Node
    	{
    		int son[26];
    		int ff,len;
    	}t[MAX];
    	int tot,last;
    	void init()
    	{
    		t[tot=1].len=-1;
    		t[0].ff=t[1].ff=1;
    	}
    	void extend(int c,int n,char *s)
    	{
    		int p=last;
    		while(s[n-t[p].len-1]!=s[n])p=t[p].ff;
    		if(!t[p].son[c])
    		{
    			int v=++tot,k=t[p].ff;
    			t[v].len=t[p].len+2;
    			while(s[n-t[k].len-1]!=s[n])k=t[k].ff;
    			t[v].ff=t[k].son[c];
    			t[p].son[c]=v;
    			Add(t[v].ff,v);
    		}
    		last=t[p].son[c];
    	}
    	int vis[MAX];
    	void dfs(int u)
    	{
    		if(t[u].len%4==0&&vis[t[u].len/2])ans=max(ans,t[u].len);
    		++vis[t[u].len];
    		for(int i=h[u];i;i=e[i].next)dfs(e[i].v);
    		--vis[t[u].len];
    	}
    }PT;
    int main()
    {
    	PT.init();
    	n=read();
    	scanf("%s",ch+1);
    	Add(1,0);
    	for(int i=1;i<=n;++i)PT.extend(ch[i]-97,i,ch);
    	PT.dfs(1);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    upd:
    我更新一下利用(half)来求解的方法
    对于每个节点,我们维护一个(half)来表示长度最长的、不超过它长度一半的那个祖先节点
    这样子只需要判断一下当前点的(half)长度是否是一半,并且当前串的长度是四的倍数就好了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 555555
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Node
    {
    	int son[26],ff;
    	int len;
    }t[MAX];
    int half[MAX];
    int tot,last;
    void init(){t[tot=1].len=-1;t[0].ff=t[1].ff=1;}
    void extend(int c,int n,char *s)
    {
    	int p=last;
    	while(s[n-t[p].len-1]!=s[n])p=t[p].ff;
    	if(!t[p].son[c])
    	{
    		int v=++tot,k=t[p].ff;
    		t[v].len=t[p].len+2;
    		while(s[n-t[k].len-1]!=s[n])k=t[k].ff;
    		t[v].ff=t[k].son[c];
    		t[p].son[c]=v;
    		if(t[v].len==1)half[v]=0;
    		else
    		{
    			int pos=half[p];
    			while(s[n-t[pos].len-1]!=s[n]||(t[pos].len+2)*2>t[v].len)
    				pos=t[pos].ff;
    			half[v]=t[pos].son[c];
    		}
    	}
    	last=t[p].son[c];
    }
    int n,ans;
    char ch[MAX];
    int main()
    {
    	scanf("%d%s",&n,ch+1);init();
    	for(int i=1;i<=n;++i)extend(ch[i]-97,i,ch);
    	for(int i=1;i<=tot;++i)
    		if(t[half[i]].len*2==t[i].len&&t[i].len%4==0)
    			ans=max(ans,t[i].len);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Struts2 技术全总结 (正在更新)
    Servlet 技术全总结 (已完成,不定期增加内容)
    字节顺序&字节对齐
    Kubernetes 清除持续 Terminating 状态的Pods
    [K8s]无yaml文件重启Pod
    外部访问docker容器(docker run -p/-P 指令)
    Linux (OpenBSD)系统目录分析
    CPU Cache 机制以及 Cache miss
    ifconfig 中的 eth0 eth0:1 eth0.1 与 lo
    MYSQL 文件类型
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8460254.html
Copyright © 2020-2023  润新知