• [BZOJ3676][Apio2014]回文串


    [BZOJ3676][Apio2014]回文串

    试题描述

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

    输入

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

    输出

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

    输入示例

    abacaba

    输出示例

    7

    数据规模及约定

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

    题解

    首先我们用 manacher 求出所有极长的回文子串,然后通过这个我们可以求出以每个位置 i 为结尾,向左延伸到的最长回文子串长度是多少(记为 len[i])。方法就是先对于极长的回文子串打一下标记,然后从后往前扫一遍,每往前移一个位置值减一,然后和当前位置的标记取个 max。

    接下来我们构造后缀自动机,对于每个状态的 right 集合,我们只要知道这个集合的大小就知道当前串出现了几次;现在我们还需要保证所有找到的串是回文的,于是就可以用上面求出来的 len[i] 做。不难发现对于一个状态 u 的 right 集合,把集合内所有位置上的 len[i] 取 min(注意判断这个 min 值必须要小于等于 Max[u])就是当前节点的答案了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    #define maxn 600010
    #define maxnode 600010
    #define maxa 26
    #define oo 2147483647
    #define LL long long
    
    char S[maxn], Str[maxn];
    int n, Len[maxn], len[maxn], alp[maxn];
    
    int rt, last, ToT, to[maxnode][maxa], par[maxnode], Max[maxnode], val[maxnode], mnl[maxnode];
    void extend(int pos) {
    	int x = Str[pos] - 'a', p = last, np = ++ToT; Max[np] = Max[p] + 1; val[np] = 1; mnl[np] = len[pos]; last = np;
    	while(p && !to[p][x]) to[p][x] = np, p = par[p];
    	if(!p){ par[np] = rt; return ; }
    	int q = to[p][x];
    	if(Max[q] == Max[p] + 1){ par[np] = q; return ; }
    	int nq = ++ToT; Max[nq] = Max[p] + 1; mnl[nq] = oo;
    	memcpy(to[nq], to[q], sizeof(to[q]));
    	par[nq] = par[q];
    	par[q] = par[np] = nq;
    	while(p && to[p][x] == q) to[p][x] = nq, p = par[p];
    	return ;
    }
    
    int sa[maxnode], Ws[maxnode];
    
    int main() {
    	scanf("%s", Str + 1);
    	n = strlen(Str + 1);
    	
    	for(int i = 1; i <= n; i++) S[(i<<1)-1] = Str[i], S[i<<1] = 'z' + 1;
    	n <<= 1;
    	for(int i = 1; i <= n; i++) alp[i] = alp[i-1] + (isalpha(S[i]) ? 1 : 0);
    	int mxp = 0;
    	for(int i = 1; i <= n; i++) {
    		int mxr = mxp + Len[mxp] - 1;
    		if(mxr >= i) Len[i] = min(Len[(mxp<<1)-i], mxr - i + 1); else Len[i] = 1;
    		while(1 <= i - Len[i] + 1 && i + Len[i] - 1 <= n && S[i-Len[i]+1] == S[i+Len[i]-1]) Len[i]++;
    		Len[i]--;
    		if(mxr < i + Len[i] - 1) mxp = i;
    	}
    	for(int i = 1; i <= n; i++) len[i+Len[i]-1] = max(len[i+Len[i]-1], Len[i]);
    //	for(int i = 1; i <= n; i++) printf("%d%c", Len[i], i < n ? ' ' : '
    '); 
    //	for(int i = 1; i <= n; i++) printf("%d%c", len[i], i < n ? ' ' : '
    '); 
    	int mx = 1;
    	for(int i = n; i; i--) {
    		mx--;
    		if(len[i] > mx) mx = len[i]; else len[i] = mx;
    	}
    //	for(int i = 1; i <= n; i++) printf("%d%c", len[i], i < n ? ' ' : '
    ');
    	for(int i = 1; i <= n; i++) {
    		len[i] = (len[i] << 1) - 1;
    		int l = len[i];
    		len[i] = alp[i] - alp[i-l];
    	}
    	for(int i = 1; i <= (n >> 1); i++) len[i] = max(len[(i<<1)-1], len[i<<1]); n >>= 1;
    //	puts(S + 1);
    //	for(int i = 1; i <= n; i++) printf("%d%c", len[i], i < n ? ' ' : '
    ');
    	rt = last = ToT = 1;
    	for(int i = 1; i <= n; i++) extend(i);
    	for(int i = 1; i <= ToT; i++) Ws[n-Max[i]]++;
    	for(int i = 1; i <= n; i++) Ws[i] += Ws[i-1];
    	for(int i = ToT; i; i--) sa[Ws[n-Max[i]]--] = i;
    	
    	LL ans = 0;
    	for(int i = 1; i <= ToT; i++) {
    		int u = sa[i];
    		mnl[par[u]] = min(mnl[par[u]], mnl[u]);
    		val[par[u]] += val[u];
    		if(Max[u] >= mnl[u]) ans = max(ans, (LL)mnl[u] * val[u]);
    	}
    	printf("%lld
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    BlogEngine.Net
    加速Web开发的9款知名HTML5框架
    个人论坛博客的代码
    Android客户端调用Asp.net的WebService
    前端总结数据结构与算法基础
    node知识点及第三方模块
    消息轮播
    el-date-picker 组件时间格式化方式
    Vue+Element前端导入导出Excel
    vue单元测试
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6557676.html
Copyright © 2020-2023  润新知