2021 ICPC沈阳 M.String Problem(思维)

题目描述

题目链接

题目大意

给你一个字符串,求这个字符串的所有前缀字符串中的最大字典序子串。

题目分析

这 个 题 的 思 路 非 常 的 简 单 。 这个题的思路非常的简单。

首 先 我 们 可 以 发 现 : 对 于 一 个 字 符 串 , 其 字 典 序 最 大 的 子 串 , 这 个 子 串 的 结 尾 一 定 是 整 个 字 符 串 的 结 尾 。 首先我们可以发现:对于一个字符串,其字典序最大的子串,这个子串的结尾一定是整个字符串的结尾。

证 明 ( 反 证 法 ) : 假 设 字 符 串 范 围 是 [ 1 , n ] , 其 字 典 序 最 大 的 子 串 范 围 是 [ l , r ] ( 1 < l < = r < n ) , 那 么 存 在 一 个 证明(反证法):假设字符串范围是[1,n],其字典序最大的子串范围是[l,r](1<l<=r<n),那么存在一个 [1,n][l,r]1<l<=r<n 子 串 [ l , n ] , 而 这 个 子 串 的 字 典 序 是 大 于 [ l , r ] 的 子 串 的 ( 如 果 两 串 前 缀 完 全 一 样 则 比 较 长 度 ) 。 子串[l,n],而这个子串的字典序是大于[l,r]的子串的(如果两串前缀完全一样则比较长度)。 [l,n][l,r]

因 此 我 们 只 需 要 找 出 前 缀 字 符 串 最 大 子 串 的 开 头 即 可 。 因此我们只需要找出前缀字符串最大子串的开头即可。

我 们 可 以 从 前 往 后 枚 举 每 一 位 , 并 记 录 下 当 前 字 典 序 最 大 的 前 缀 , 以 这 个 前 缀 的 开 头 到 枚 举 的 整 个 前 缀 的 结 尾 来 我们可以从前往后枚举每一位,并记录下当前字典序最大的前缀,以这个前缀的开头到枚举的整个前缀的结尾来 作 为 字 典 序 最 大 的 子 串 。 作为字典序最大的子串。

代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <algorithm>
#include <iomanip>
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=1e6+5,mod=1e9+7;
int l[N];
char s[N];
int main()
{
	scanf("%s",s+1);
    int n=strlen(s+1);
	for(int i=1;i<=n;)			//枚举字符串的每一位
	{
		if(!l[i]) l[i]=i;		//如果这一位之前没有记录,那么其最大字串为[i,i]
		int j=i,k=i+1;
		while(k<=n&&s[j]>=s[k])	//更新所有以i为开头,以k为结尾的最大子串
		{
			if(!l[k]) l[k]=i;	//如果当前位没被记录过,则以i为开头的子串为其最大子串
			if(s[j]==s[k]) j++;	//如果当前位j与位k相等,则j+1,继续向后比较(直到决定出谁才是字典序最大的前缀)
			else j=i;			//如果不相等还在while里,说明以i开头的前缀还是最大的前缀(比较结束,j从新置i)
			k++;
		}
		while(i<=j) i+=k-j; 	//跳出了上一个while,说明[i,j]这个前缀字典序小于后面某个子串,则跳到j之后
	}
	for(int i=1;i<=n;i++) printf("%d %d\n",l[i],i);
	return 0;
}
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值