[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 }