暂无连接
字符串最大值
【问题描述】
少年易学老难成,一寸光阴不可轻。
一个字符串的前缀是指包含该字符第一个字母的连续子串,例如: 的所有前缀为 。
给出一个字符串 ,求其所有前缀中,字符长度与出现次数的乘积的最大值。
例如: 所有的前缀如下:
, 长度与出现次数的乘积
,
,长度与出现次数的乘积
,
, 长度与出现次数的乘积
,
, 长度与出现次数的乘积
,
, 长度与出现次数的乘积
,
, 长度与出现次数的乘积
,
, 长度与出现次数的乘积
。
其中”ababa”出现了 次,二者的乘积为 ,是所有前缀中最大的。
【输入格式】
输入字符串 , 中的所有字符均为小写英文字母。
【输出格式】
输出所有前缀中字符长度与出现次数的乘积的最大值。
【输入样例】
abababa
【输出样例】
10
【样例说明】
出现了两次
【数据范围】
对 的输入数据 : ;
对 的输入数据 : ;
对 的输入数据 : ;
对 的输入数据 : , 为 的长度。
数据非常有梯度。
题解
AC自动机天下第一,KMP辣鸡。
直接插入原串再用原串匹配一下,匹配完后拓扑递推一下即可统计答案。
但是裸的 自动机会 ,因为 退化成了一条链,所以就不用开 了。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e6+5;
char ch[M];
int len,tot,t[M],fail[M],son[M],nxt[M];
queue<int>dui;
void in(){scanf("%s",ch+1);}
void ins()
{
int v=0,s;
for(int i=1;i<=len;++i)
{
s=ch[i]-'a';
if(!son[v])son[v]=++tot;
nxt[v]=s,v=son[v];
}
}
void bfs()
{
int v,p;dui.push(0);
while(!dui.empty())
{
v=dui.front();dui.pop();
for(int i=0;i<26;++i)
{
if(nxt[v]!=i)continue;
if(!v)fail[son[v]]=0;
else
{
for(p=fail[v];~p;p=fail[p])if(nxt[p]==i){fail[son[v]]=son[p];break;}
if(p==-1)fail[son[v]]=0;
}
if(son[v])dui.push(son[v]);
}
}
}
void cmp()
{
int v=0,s,p;
for(int i=1;i<=len;++i)
{
s=ch[i]-'a';
while(v&&nxt[v]!=s)v=fail[v];
if(nxt[v]==s)v=son[v];
++t[v];
}
}
void ac()
{
len=strlen(ch+1);fail[0]=-1;
ins();bfs();cmp();long long ans=0;
for(int i=len;i>=1;--i)t[fail[i]]+=t[i],ans=max(ans,1ll*i*t[i]);
printf("%lld",ans);
}
int main(){in();ac();}