• 【洛谷P3649】回文串


    题目大意:给定一个长度为 N 的字符串,定义一个变量为该字符串的回文子串长度乘以该字串出现的次数,求这个变量的最大值是多少。

    题解:学会了回文自动机。
    回文自动机是两棵树组成的森林结构,并通过 fail 指针构成一棵回文树结构。
    回文树的节点存储的是每个子串的最长回文后缀,最长回文后缀的定义是:除了字串本身的最长的回文后缀。
    可以证明回文树的节点数和边数是 (O(|S|)) 的。
    建立回文树采用增量法,时间复杂度为 (O(|S|))

    本题对于每个回文树节点,维护一个出现次数的变量。最后按照节点从后到前的顺序,将每个点的出现次数累加到其父节点(fail 节点)的出现次数中,并更新答案即可。

    代码如下

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+10;
    typedef long long LL;
    
    char s[maxn];
    int n; LL ans;
    struct PAM{
    	int tot,last,trie[maxn][26],fail[maxn],len[maxn],sz[maxn];
    	PAM(){tot=1,fail[0]=fail[1]=1,len[1]=-1;}
    	void extend(int c,int i){
    		int p=last;
    		while(s[i-len[p]-1]!=s[i])p=fail[p];
    		if(!trie[p][c]){
    			int now=++tot,k=fail[p];
    			while(s[i-len[k]-1]!=s[i])k=fail[k];
    			len[now]=len[p]+2,fail[now]=trie[k][c],trie[p][c]=now;
    		}
    		last=trie[p][c],++sz[last];
    	}
    	void solve(){
    		for(int i=tot;i>1;i--){
    			sz[fail[i]]+=sz[i];
    			ans=max(ans,(LL)len[i]*sz[i]);
    		}
    	}
    }pam;
    
    int main(){
    	scanf("%s",s+1),n=strlen(s+1);
    	for(int i=1;i<=n;i++)pam.extend(s[i]-'a',i);
    	pam.solve();
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    jvm 垃圾收集器
    MySQL 查询结果去除边框
    MySQL5.7 半同步复制技术
    MySQL 5.7半同步复制技术 zero
    redis 迁移工具 redisshake
    MySQL 如何找出占用CPU较高的SQL
    部署redis sentinel
    MySQL的SQL_CALC_FOUND_ROWS 类似count(*)
    MongoDB 副本集删除超级用户后恢复
    【Linux】关于 Systemd/Journal
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10786033.html
Copyright © 2020-2023  润新知