[bzoj4974] 字符串大师

 

题解:给出一个字符串s,定义per_i为s_i的长度为i的前缀的最小循环节,现在给出per_i (i=1~n),要求你还原字符串s,s的字典序要求最小

 

题解:

per_i=i-next_i,但是好像跟此题没有太大的关系

分两种情况讨论:

1、i==per_i,相当于知道循环节和循环串要求后面某个位置的字符,那么直接从之前的循环串推过来即可

2、i!=per_i,表示不能参与到之前的循环串中,类似于next数组的构造,记录下哪些字符在循环串中出现过,删去后从小到大取即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #define ll long long
 8 #define N 100010
 9 using namespace std;
10 
11 int per[N];
12 char s[N];
13 bool vis[N];
14 
15 int gi() {
16   int x=0,o=1; char ch=getchar();
17   while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
18   if(ch=='-') o=-1,ch=getchar();
19   while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
20   return o*x;
21 }
22 
23 int main() {
24   int n=gi();
25   for(int i=1; i<=n; i++) per[i]=gi();
26   s[1]='a';
27   for(int i=2; i<=n; i++) {
28     if(i!=per[i]) s[i]=s[(i-1)%per[i]+1];
29     if(i==per[i]) {
30       memset(vis,0,sizeof(vis));
31       int j=i-1;
32       while(j!=per[j]) {
33     j=(j-1)%per[j]+1;
34     vis[s[j+1]-'a']=1;
35       }
36       for(int k=1; k<26; k++) {
37     if(!vis[k]) {s[i]=k+'a';break;}
38       }
39     }    
40   }
41   printf("%s\n", s+1);
42   return 0;
43 }

 

posted @ 2017-09-25 16:41  HLX_Y  阅读(187)  评论(0编辑  收藏  举报