模板串33

题目大意

若将一个串 B B B 复制多遍,然后拼接起来,拼接时可将两个模板串相同的部分叠起来,最后得到一个串 A A A

我们称串 B B B 是串 A A A 的模板串。

现给定一个字符串,试求出这个字符串的最短模板串,输出这个长度。

解题思路

考虑一个串 A A A 的,他的最短模板串为 B B B,那么具体组成就是这样:

_______________ A A A

____----------- B B B

---____-------- B B B

------____----- B B B

--------____--- B B B

---------____-- B B B

-----------____ B B B

发现,一个串的模板串只能是这个串的前缀。

那么设 f i f_i fi [ 1 , i ] [1,i] [1,i] 的最小模板串的长度。

g i g_i gi 为 长度为 i i i 的模板串最后出现的下标。

那么边界为 f i = i f_i=i fi=i

考虑转移,如果 g [ f [ n x t [ i ] ] ] < ∣ i − n x t [ i ] ∣ g[f[nxt[i]]]<|i-nxt[i]| g[f[nxt[i]]]<inxt[i],即两个模板串之间不相交,不可转移( ∣ x ∣ |x| x x x x 的长度)。

如果 g [ f [ n x t [ i ] ] ] > = ∣ i − n x t [ i ] g[f[nxt[i]]]>=|i-nxt[i] g[f[nxt[i]]]>=inxt[i],即两个模板串之间相交(即 [ 1 , i ] [1,i] [1,i] 1 , n x t [ i ] ] 1,nxt[i]] 1,nxt[i]] 的模板串长度相同),可以转移:

f[i] = f[nxt[i]];

其实挺有趣的。

AC CODE

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

void write(int x)
{
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

#define _ 5000005

int n;

char s[_];

int nxt[_];

int t[_];

int f[_];

signed main()
{
	scanf("%s", s + 1);
	n = strlen(s + 1);
	nxt[0] = -1;
	for(int i = 2, j = 0; i <= n; ++i)
	{
		while(~j && s[j + 1] != s[i]) j = nxt[j];
		nxt[i] = ++j;
	}
//	for(int i = 1; i <= n; ++i) cout << nxt[i] << " ";
//	cout << endl;
	for(int i = 1; i <= n; ++i)
	{
		f[i] = i;
		if(t[f[nxt[i]]] >= i - nxt[i]) f[i] = f[nxt[i]];
		t[f[i]] = i;
	}
	write(f[n]);
	putchar('\n');
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值