模板串

题目大意

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

我们称串 BB 是串 AA 的模板串。

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

解题思路

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

_______________ AA

____----------- BB

---____-------- BB

------____----- BB

--------____--- BB

---------____-- BB

-----------____ BB

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

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

gig_i 为 长度为 ii 的模板串最后出现的下标。

那么边界为 fi=if_i=i

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

如果 g[f[nxt[i]]]>=inxt[i]g[f[nxt[i]]]>=|i-nxt[i],即两个模板串之间相交(即 [1,i][1,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;
}
posted @ 2021-10-07 16:26  蒟蒻orz  阅读(2)  评论(0编辑  收藏  举报  来源