Codeforces 30 E

题意:
一个长度为奇数的回文串可以写成a+b+a的形式,b的长度也是奇数,aa的反串。我们设S=x+a+y+b+z+a,其中x,y,z为任意可以为空的字符串。
给定S,求原来回文串的最长长度,以及a,b,aS中的起始位置和长度。

题解:
有一个关键的贪心结论:

假设我们已经定下了b的中心点为i,那么最长的原串,一定是让b的长度尽可能长,其次让a,a的长度尽可能长。

证明:

如果有b可以去更短的串,分两种情况讨论:

  1. a,ab相邻:那么我们可以让b为整个回文串a+b+b,不影响答案。
  2. a,a其中一个和b相邻、或两个都不和b相邻:那如果b不是以i为中心最长的回文串,那么我们完全可以将b向两侧各延伸一格,不会使得答案更劣。

所以,我们先求出以i为中心最长回文串,设其长度为2pi1,这个可以使用manacher求出。(由于只要求长度为奇数的回文串,所以我们甚至没必要加分隔符)

然后我们枚举中心点i,找到最长的a,a

发现aS的一个后缀,那么我们就可以将模式串S和匹配串S进行KMP,得到f(i)表示以i结尾S的前缀 的后缀,最多能匹配多少S的前缀。

那么我们求得的f(i)就是ai结尾的最大长度。

所以为了求ipif(i)的min,我们可以使用前缀max。注意a也不能和p相交,所以我们还要求从在a最大时a的起始位置,和i+pi取max,才是真正的长度。

时间复杂度为O(n)

代码:

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
 
const int maxn=100005;
int n,ans,x,y,p[maxn],nxt[maxn],f[maxn],id[maxn];
char str[maxn],istr[maxn];
 
void manacher() {
	int mid=0,mr=0;
	for(int i=1;i<=n;i++) {
		if(i<=mr) p[i]=std::min(p[mid+mid-i],mr-i+1);
		else p[i]=1;
		while(i+p[i]<=n&&i-p[i]>=1&&str[i+p[i]]==str[i-p[i]]) p[i]++;
		if(i+p[i]-1>mr) mr=i+p[i]-1,mid=i;
	}
}
 
void kmp() {
	for(int i=2,j=0;i<=n;i++) {
		while(j&&istr[j+1]!=istr[i]) j=nxt[j];
		if(istr[j+1]==istr[i]) j++;
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=n;i++) {
		while(j&&istr[j+1]!=str[i]) j=nxt[j];
		if(istr[j+1]==str[i]) j++;
		f[i]=j;
		if(j==n) j=nxt[j];
	}
}
 
int main() {
	scanf("%s",str+1); n=strlen(str+1);
	for(int i=1;i<=n;i++) istr[i]=str[n-i+1];
	manacher(); kmp();
	for(int i=1;i<=n;i++)
		if(f[i]>f[i-1]) id[i]=i;
		else id[i]=id[i-1],f[i]=f[i-1];
	for(int i=1;i<=n;i++) {
		int longest=f[i-p[i]];
		longest=std::min(longest,n-(i+p[i]-1));
		int trans=2*longest+2*p[i]-1;
		if(trans>ans) {
			ans=trans;
			x=id[i-p[i]],y=i;
		}
	}
	std::pair<int,int> s1(x-f[x]+1,x),s2(y-p[y]+1,y+p[y]-1),s3(n-f[x]+1,n);
	if(s1.first<=s1.second) {
		printf("3\n%d %d\n%d %d\n%d %d\n",s1.first,s1.second-s1.first+1,
		s2.first,s2.second-s2.first+1,s3.first,s3.second-s3.first+1);
	} else {
		printf("1\n%d %d\n",s2.first,s2.second-s2.first+1);
	}
	return 0;
}
posted @   Nastia  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示