1. 程式人生 > >[KMP]BZOJ 4974 [Lydsy1708月賽]字串大師 題解

[KMP]BZOJ 4974 [Lydsy1708月賽]字串大師 題解

題目大意

給出一個長度為n的字串,求這個字串的所有字首的最小迴圈節,現在反過來,給出所有字首的最小迴圈節,求字典序最小的字串。(N100000)(N\le100000)

解題分析

最小迴圈節=i-nxt[i]

那麼可以求出nxt陣列。

求出來了又如何?

如果Nxt[i]已知,注意nxt[i]的定義是s[1…nxt[i]]=s[i-nxt[i]+1…n],那麼明顯s[i]=s[nxt[i]]

但如果nxt[i]=0,那怎麼辦?

注意到字串只由小寫字母構成,也就是最多26個元素,那麼可以1個1個試試看,代入用前面的nxt陣列驗證。

然後好了。

示例程式碼

題目傳送門

#include<cstdio>
#include<cstring>
using namespace std;
int n,tot,nxt[100005];
char s[100005];
int main()
{
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	scanf("%d",&n);
	for (int i=1,x;i<=n;i++){
		scanf("%d",&x); nxt[i]=i-x;
		if (i==1) {s[1]='a'; continue;}
		if (nxt[i]) s[i]=s[nxt[i]]; else{
			for (int z=0,j;z<26;z++){
				s[i]='a'+z; j=nxt[i-1];
				while (j&&s[j+1]!=s[i]) j=nxt[j];
				if (s[j+1]!=s[i]&&!j) break;
			}
		}
	}
	for (int i=1;i<=n;i++) putchar(s[i]);
	return 0;
}