[KMP]P3426

对于字符串刻印章,使每个字符都能被印出来,并且不能印上其他字符。求印章最短长度。 ∣ S ∣ ≤ 5 × 1 0 5 |S|\leq 5\times 10^5 S5×105


看到题目第一感觉是KMP,但具体实现很费脑筋。

先举个例子:

12345678910111213
s[i]ababbababbaba
nxt[i]0012012345678

f [ i ] f[i] f[i] 表示前 i i i 个字符的答案,那么 f [ i ] f[i] f[i] 只有可能等于以下两种之一:

1.用一个长度为i的印章, f [ i ] = i f[i]=i f[i]=i

2.能盖住 n x t [ i ] nxt[i] nxt[i] 的印章有可能能盖住 s [ 1... i ] s[1...i] s[1...i] , f [ i ] = f [ n x t [ i ] ] f[i]=f[nxt[i]] f[i]=f[nxt[i]] 我们具体分析这种情况:

首先,根据 f [ n x t [ i ] ] f[nxt[i]] f[nxt[i]] 的定义, s [ 1... n x t [ i ] ] s[1...nxt[i]] s[1...nxt[i]] 一定能被覆盖,同时又因为 s [ 1... n x t [ i ] ] = s [ i − n x t [ i ] . . . i ] s[1...nxt[i]]=s[i-nxt[i]...i] s[1...nxt[i]]=s[inxt[i]...i] ,所以只用考虑 s [ n x t [ i ] . . . i − n x t [ i ] ] s[nxt[i]...i-nxt[i]] s[nxt[i]...inxt[i]] 的情况。最简单的方法就是看在 f [ i − n x t [ i ] . . . i − 1 ] f[i-nxt[i]...i-1] f[inxt[i]...i1] 之间是否还有别的 f [ j ] = f [ n x t [ i ] ] f[j]=f[nxt[i]] f[j]=f[nxt[i]] ,如果有就可以更新 f [ i ] f[i] f[i]

#include<bits/stdc++.h>
using namespace std;

char s[500005];
int nxt[500005],f[500005],t[500005];

int main()
{
	scanf("%s",s+1);
	int slen=strlen(s+1);
	for(int i=2,j=0;i<=slen;++i)
	{
		while(j && s[i]!=s[j+1])
			j=nxt[j];
		if(s[i]==s[j+1])
			j++;
		nxt[i]=j;
	}
	for(int i=1;i<=slen;++i)
	{
		f[i]=i;
		if(t[f[nxt[i]]]>=i-nxt[i])
			f[i]=f[nxt[i]];
		t[f[i]]=i;
	}
	printf("%d",f[slen]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值