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。
。给定一个长度为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),表示每个前缀的最短循环节长度。
输入数据保证至少存在一组可行解。
第二行包含n个正整数per_1,per_2,...per_n(1<=per_i<=i),表示每个前缀的最短循环节长度。
输入数据保证至少存在一组可行解。
Output
输出一行一个长度为n的小写字符串S,即某个满足条件的S。
若有多个可行的S,输出字典序最小的那一个。
若有多个可行的S,输出字典序最小的那一个。
Sample Input
5
1 2 2 2 5
Sample Output
ababb
sol:1~n位最短循环节的长度=n-next(n),那么next(n)=n-循环节长度。本题模拟数据如下:
10 //字串长度为10
1 1 3 4 4 4 7 7 7 7 //对于每一位截至的前缀,最小循环节长度
0 1 0 0 1 2 0 1 2 3 //根据n-循环节长度,求得每一位的next值
a //字典序最小,第1位定为a。
a a //next[2]=1,则说明第2位与第1位相等。
a a b //next[3]=0,说明第3位与next[3-1]+1不等,即第3位与第2位不等,回退,第3位与next[2-1]+1位,即第1位,也不等,按顺序取到b。
a a b b //next[4]=0,说明第4位与next[4-1]+1不等,即第4位与第1位不等,按顺序取到b。
a a b b a //第5位与第1位相等。
a a b b a a //第6位与第2位相等。
a a b b a a c //next[7]=0,说明与next[6-1]+1,即第3位不等,回退,与next[3-1]+1,即第2位也不等,回退,与next[2-1]+1,即第1位也不等,第7位按顺序取到c。
......
a a b b a a c a a b //最后结果
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,nxt[100001]; 4 char s[100001]; 5 bool flag[26]; 6 int main() { 7 scanf("%d",&n); 8 for(int i=1;i<=n;i++) //求出真实的nxt数组 9 { 10 scanf("%d",nxt+i); 11 nxt[i]=i-nxt[i]; 12 } 13 s[1]='a'; //第一个位置当然是放a 14 for(int i=2;i<=n;i++)//一路扫过去 15 { 16 if(nxt[i])//如果大于零,可直接算出当前这一位的字母是哪一个 17 { 18 s[i]=s[nxt[i]]; 19 } 20 else 21 { 22 //如果为0,则说明有些字母是不能取的 23 int p=nxt[i-1]+1;//P代表,当前字符不能为字符串中第P个字符 24 memset(flag,false,sizeof(flag)); 25 flag[0]=true;//字母a已取过了 26 while(p!=1) 27 { 28 flag[s[p]-'a']=true; 29 p=nxt[p-1]+1; 30 } 31 for(int j=0;j<26;j++) // 找出第一个能取的字符出来 32 { 33 if(!flag[j]) 34 { 35 s[i]=j+'a'; 36 break; 37 } 38 } 39 } 40 } 41 s[n+1]='