51Nod 1277 字符串中的最大值 KMP next数组经典应用

本文介绍了一种利用KMP算法求解字符串所有前缀中字符长度与出现次数乘积最大值的方法。通过构造next数组追踪前缀重复情况,并结合计数技巧高效求得答案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接


一个字符串的前缀是指包含该字符第一个字母的连续子串,例如: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,是所有前缀中最大的。
Input
输入字符串S, (1 <= L <= 100000, L为字符串的长度),S中的所有字符均为小写英文字母。
Output
输出所有前缀中字符长度与出现次数的乘积的最大值。
Sample Input
abababa
Sample Output
10



思路:

KMP next 数组的经典应用.

再说一次next数组的含义: next【i】 表示当前匹配到第i个字符,前缀与后缀的最长公共长度. 

这里可以理解为以i结尾的前缀包含 长度为next【i】的前缀

那么我们先对这个串做一次KMP,用cnt[i]记录长度为i的前缀出现的次数,显然初始都为1,我们从后往前遍历,遍历到当前以i为结尾的前缀时,因为next[i]表示以i结尾的字符的前后缀最长长度,累加就好.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define inf 0x3f3f3f3f
using namespace std;

typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+10;
int nxt[maxn];
int cnt[maxn]; 

char s[maxn];
int len;
void get_nxt()
{
	nxt[0] = -1;
	int i = 0,j = -1;
	while(i <= len)
	{
		if(j == -1 || s[i] == s[j])
		nxt[++i] = ++j;
		else
		j = nxt[j];
	}
 } 

int main()
{
		scanf("%s",s);
		len=strlen(s);
		get_nxt();
		ll ans=0;
		for(int i = len;i>=1;i--)
		{
			cnt[i] ++;
			cnt[nxt[i]] += cnt[i];
		}
		for(int i = 1;i <= len;i++)
		ans = max(ans,(ll)i*cnt[i]);
		printf("%lld\n",ans);
	return 0;
}

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值