1. 程式人生 > >[BZOJ4947] 字符串大師 - KMP

[BZOJ4947] 字符串大師 - KMP

() 字典序 ios esp pri str 多個 reg problem

4974: [Lydsy1708月賽]字符串大師

Time Limit: 1 Sec Memory Limit: 256 MB
Submit: 739 Solved: 358
[Submit][Status][Discuss]

Description

一個串T是S的循環節,當且僅當存在正整數k,使得S是T^k(即T重復k次)的前綴,比如abcd是abcdabcdab的循環節 。給定一個長度為n的僅由小寫字符構成的字符串S,請對於每個k(1<=k<=n),求出S長度為k的前綴的最短循環節的 長度per_i。字符串大師小Q覺得這個問題過於簡單,於是花了一分鐘將其AC了,他想檢驗你是否也是字符串大師。 小Q告訴你n以及per_1,per_2,...,per_n,請找到一個長度為n的小寫字符串S,使得S能對應上per。

Input

第一行包含一個正整數n(1<=n<=100000),表示字符串的長度。 第二行包含n個正整數per_1,per_2,...per_n(1<=per_i<=i),表示每個前綴的最短循環節長度。 輸入數據保證至少存在一組可行解。

Output

輸出一行一個長度為n的小寫字符串S,即某個滿足條件的S。 若有多個可行的S,輸出字典序最小的那一個。

Sample Input

5
1 2 2 2 5

Sample Output

ababb

HINT

Source

claris原創,本oj版權所有,翻版必究

[Submit][Status][Discuss]
題解: 我們由最短循環節=i-nxt[i],可以求出每個nxt。 然後貪心地求出答案。 每一位如果它nxt不為0,直接ans[i]=ans[xt[i]]; 如果它等於0,那麽考慮kmp的過程,沿著nxt[i-1]一直往前跑找到的每一個j,ans[j+1]都不能是現在的ans[i],然後每次取未出現過的字典序最小的字母即可;
Code:
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <map>
 4 using namespace std;
 5
6 int n; 7 int nxt[100010]; 8 char ans[100010]; 9 10 int main() 11 { 12 scanf("%d", &n); 13 for (register int i = 1 ; i <= n ; i ++) 14 { 15 int x; 16 scanf("%d", &x); 17 nxt[i] = i - x; 18 } 19 nxt[0] = -1; 20 ans[1] = a; 21 22 for (register int i = 2 ; i <= n ; i ++) 23 { 24 if (nxt[i] > 0) ans[i] = ans[nxt[i]]; 25 else 26 { 27 map <char, bool> mp; 28 mp.clear(); 29 int las = nxt[i-1] + 1; 30 while (las) 31 { 32 mp[ans[las]] = 1; 33 las = nxt[las-1] + 1; 34 } 35 for (register int j = a ; j <= z ; j ++) 36 { 37 if (!mp[j]) {ans[i] = j;break;} 38 } 39 } 40 } 41 for (register int i = 1 ; i <= n ; i ++) printf("%c", ans[i]); 42 return 0; 43 }

[BZOJ4947] 字符串大師 - KMP