ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LGP3426题解

2022-01-28 12:01:58  阅读:116  来源: 互联网

标签:LGP3426 前缀 题解 印章 ui 轰入 fail dp


真是不管什么时候来做这道题都会觉得很神仙呐。。。

观察一下,如果存在一个合法的印章,那么这个印章一定是这个串的前缀,也是这个串的后缀。

即合法的印章一定是原串的 \(\rm Border\)。

于是设 \(dp[n]\) 为 \([1,n]\) 这个前缀的最短的印章长度。这个印章就是 \([1,dp[n]]\)。

注意到 \(dp[fail[n]]\) 的长度不可能大于 \(dp[n]\),所以 \(dp[n]\) 其实只有两种决策:\(n\) 和 \(dp[fail[n]]\)。

于是开始思考满足什么条件的情况下才能够使用 \(dp[fail[n]]\)。

注意到 \([1,dp[fail[n]]]\) 一定是 \([1,n]\) 的后缀,所以我们假设这个印章已经把这个后缀狂暴轰入了,那么 \([1,n-dp[fail[n]]]\) 还没有被轰入。所以条件就是 \([1,n-dp[fail[n]]+1]\sim [1,n]\) 这几个前缀中的某一个的前缀的 \(dp\) 值为 \(dp[fail[n]]\)。(也就是轰入这个前缀之后,再使用这个印章轰入后缀。)

看似需要维护区间 \(\max\)?其实并不需要,只需要对每一个 \(dp\) 值维护最右边的下标即可。

代码很短,但是思维量是很多的。

#include<cstring>
#include<cstdio>
typedef unsigned ui;
const ui M=5e5+5;
ui n,dp[M],mx[M],fail[M];char s[M];
signed main(){
	ui i,j;scanf("%s",s+1);n=std::strlen(s+1);
	for(i=1,j=0;i<=n;++i){
		if(i==1)fail[i]=0,dp[i]=1,mx[1]=1;
		else{
			while(j&&s[j+1]!=s[i])j=fail[j];if(s[j+1]==s[i])++j;fail[i]=j;
			if(mx[dp[j]]>=i-j)dp[i]=dp[j];else dp[i]=i;mx[dp[i]]=i;
		}
	}
	printf("%u",dp[n]);
}

标签:LGP3426,前缀,题解,印章,ui,轰入,fail,dp
来源: https://www.cnblogs.com/lmpp/p/15852370.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有