b_51_字符串中的最大值(next数组+倒序递推)

一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcd的所有前缀为a, ab, abc, abcd。
给出一个字符串S,求其所有前缀中,字符长度与出现次数的乘积的最大值。
例如:S = "abababa" 所有的前缀如下:

"a", 长度与出现次数的乘积 1 * 4 = 4,
"ab",长度与出现次数的乘积 2 * 3 = 6,
"aba", 长度与出现次数的乘积 3 * 3 = 9,
"abab", 长度与出现次数的乘积 4 * 2 = 8,
"ababa", 长度与出现次数的乘积 5 * 2 = 10,
"ababab", 长度与出现次数的乘积 6 * 1 = 6,
"abababa", 长度与出现次数的乘积 7 * 1 = 7.

其中"ababa"出现了2次,二者的乘积为10,是所有前缀中最大的。

思路
利用nx[j]表示,子串t[0:j]中最长公共前后缀的长度,假如当前位置j所对应的子串为t[0:j]
t[0:j]中有后缀t[k:j],则nx[j]=len时,则证明前缀t[0:len]和t[k:j]是相等的,也就是出现了两次
依次类推(根据next数组使指针倒退的含义,我们应该倒着做)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll n,ans,nx[N],f[N];
void get_nx(char s[]) {
    for (int i=2,j=0; i<=n; i++) {
        while (j && s[i]!=s[j+1]) j=nx[j];
        if (s[i]==s[j+1]) j++;
        nx[i]=j;
    }
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    char s[N]; cin>>s+1;
    n=strlen(s+1);
    get_nx(s);
    for (int i=1; i<=n; i++) f[i]=1;
    for (int i=n; i; i--) f[nx[i]]+=f[i];
    for (int i=1; i<=n; i++) ans=max(ans,i*f[i]);
    cout<<ans;
    return 0;
}
posted @ 2020-10-23 16:31  童年の波鞋  阅读(150)  评论(0编辑  收藏  举报