zoukankan      html  css  js  c++  java
  • [bzoj3676] [Apio2014] 回文串

    Description

    考虑一个只包含小写拉丁字母的字符串 (s) 。我们定义 (s) 的一个子串 (t) 的“出
    现值”为 (t)(s) 中的出现次数乘以 (t) 的长度。请你求出 (s) 的所有回文子串中的最
    大出现值。

    Input

    输入只有一行,为一个只包含小写字母 (a-z) 的非空字符串 (s)

    Output

    输出一个整数,为逝查回文子串的最大出现值。

    Sample Input

    【样例输入1】

    abacaba

    【样例输入2】

    www

    Sample Output

    【样例输出1】

    7

    【样例输出2】

    4

    HINT

    一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。

    在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中:

    ● a出现4次,其出现值为4:1:1=4

    ● b出现2次,其出现值为2:1:1=2

    ● c出现1次,其出现值为l:1:l=l

    ● aba出现2次,其出现值为2:1:3=6

    ● aca出现1次,其出现值为1=1:3=3

    ●bacab出现1次,其出现值为1:1:5=5

    ● abacaba出现1次,其出现值为1:1:7=7

    故最大回文子串出现值为7。

    【数据规模与评分】

    数据满足1≤字符串长度≤300000。


    想法

    做法一:回文树

    算是模板题吧。
    由于本质不同的回文串个数不超过 (|S|) ,我们考虑统计每个回文串出现次数。
    考虑在增量建树时,每增一个点都找到了以它为结尾最长回文后缀 (x) 及 其 (fail) 值,那么加入这个点,增加的回文串就是 (x)(x) 一路 (fail) 上去经过的所有节点。
    但每增一个点都统计一遍有点慢,于是记下来最后在 (fail) 树上统一 (dp) 出答案即可。

    做法二:后缀自动机+ (manacher)

    先把字符串加到后缀自动机中,预处理 (endpos) 集合大小,即子串出现次数。
    进行 (manacher) 算法时,如果 (mx) 往后扩展了,说明可能形成了一个本质不同的字符串,于是用后缀自动机统计它的出现次数。
    (parent) 树上倍增找到该结点即可。


    代码

    回文树

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int N = 300005;
    typedef long long ll;
    
    char s[N];
    int n;
    
    int cnt,fail[N],len[N],t[N],ch[N][26],last;
    void init(){ fail[0]=fail[1]=1; len[1]=-1; last=cnt=1; }
    void insert(int i,int c){
    	int p=last;
    	for(;s[i-len[p]-1]!=s[i];) p=fail[p];
    	if(ch[p][c]) { t[ch[p][c]]++;/**/ last=ch[p][c]; return; }
    	int x=++cnt,k=fail[p];
    	for(;s[i-len[k]-1]!=s[i];) k=fail[k];
    	fail[x]=ch[k][c]; 
    	len[x]=len[p]+2; ch[p][c]=x;
    	t[x]++; last=x;
    }
    
    int in[N],que[N],hd,tl;
    ll ans;/**/
    void cal(){
    	for(int i=2;i<=cnt;i++) in[fail[i]]++;
    	hd=tl=0;
    	for(int i=2;i<=cnt;i++) if(in[i]==0) que[tl++]=i;
    	while(hd<tl){
    		int x=que[hd++];
    		if(x==1) break;
    		ans=max(ans,1ll*t[x]*len[x]);
    		t[fail[x]]+=t[x]; in[fail[x]]--;
    		if(in[fail[x]]==0) que[tl++]=fail[x];
    	}
    }
    
    int main()
    {
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	
    	init();
    	for(int i=1;i<=n;i++) insert(i,s[i]-'a');
    	cal();
    	
    	printf("%lld
    ",ans);
    	
    	return 0;
    } 
    
  • 相关阅读:
    HDU 5444 Elven Postman 二叉排序树
    HDU 5438 Ponds dfs模拟
    Gym
    markdown test
    Gym
    集训回顾
    UVALive
    UVALive
    UVALive
    codeforcres 589 J
  • 原文地址:https://www.cnblogs.com/lindalee/p/12046265.html
Copyright © 2011-2022 走看看