暂无连接
字符串最大值
【问题描述】
少年易学老难成,一寸光阴不可轻。
一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcdabcd 的所有前缀为a,ab,abc,abcda,ab,abc,abcd。
给出一个字符串 SS,求其所有前缀中,字符长度与出现次数的乘积的最大值。
例如: 所有的前缀如下:
"a""a", 长度与出现次数的乘积 1∗4=41∗4=4,
"ab""ab",长度与出现次数的乘积 2∗3=62∗3=6,
"aba""aba", 长度与出现次数的乘积 3∗3=93∗3=9,
"abab""abab", 长度与出现次数的乘积 4∗2=84∗2=8,
"ababa""ababa", 长度与出现次数的乘积 5∗2=105∗2=10,
"ababab""ababab", 长度与出现次数的乘积 6∗1=66∗1=6,
"abababa""abababa", 长度与出现次数的乘积 7∗1=77∗1=7。
其中”ababa”出现了 22 次,二者的乘积为 ,是所有前缀中最大的。
【输入格式】
输入字符串 TT, 中的所有字符均为小写英文字母。
【输出格式】
输出所有前缀中字符长度与出现次数的乘积的最大值。
【输入样例】
abababa
【输出样例】
10
【样例说明】
ababaababa 出现了两次
【数据范围】
对 20%20%的输入数据 :1<=L<=1001<=L<=100;
对 40%40%的输入数据 :1<=L<=10001<=L<=1000;
对 50%50%的输入数据 :1<=L<=50001<=L<=5000;
对 100%100%的输入数据 :1<=L<=10000001<=L<=1000000, LL 为 的长度。
数据非常有梯度。
题解
AC自动机天下第一,KMP辣鸡。
直接插入原串再用原串匹配一下,匹配完后拓扑递推一下即可统计答案。
但是裸的ACAC自动机会MLEMLE,因为TrieTrie退化成了一条链,所以就不用开M×26M×26了。
代码
#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();}
AC自动机求字符串前缀最大值

本文介绍使用AC自动机解决一个字符串问题的方法,即寻找一个字符串的所有前缀中,字符长度与出现次数乘积的最大值。通过构建AC自动机并进行匹配统计,最终得出最优解。
1万+

被折叠的 条评论
为什么被折叠?



