bzoj 4974 [Lydsy八月月赛]字符串大师

题目大意:

一个串T是S的循环节 当且仅当存在正整数k 使得S是T重复k次的前缀 比如abcd是abcdabcdab的循环节

给定一个长度为n的仅由小写字符构成的字符串S 请对于每个k(1<=k<=n) 求出S长度为k的前缀的最短循环节的长度per_i

已知per_1,per_2,...,per_n 请找到一个长度为n的小写字符串S 使得S能对应上per

思路:

若一个per i!=i 直接模一下在之前的里面找就行了

若不是 找到一些之前循环中出现的字符,这些字符如果出现在这一位会导致循环per改变

仿照next数组的思路 找出来 加上字典序最小的一个可用字符

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<queue>
 8 #include<map>
 9 #include<vector>
10 #define ll long long
11 #define inf 2147483611
12 #define MAXN 1000100
13 #define MOD 1000000
14 using namespace std;
15 inline int read()
16 {
17     int x=0,f=1;char ch=getchar();
18     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
19     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
20     return x*f;
21 }
22 int n,a[MAXN],cnt,hsh[30],j;
23 char ans[MAXN];
24 int main()
25 {
26     n=read();
27     for(int i=1;i<=n;i++) a[i]=read();
28     ans[1]='a';
29     for(int i=2;i<=n;i++)
30     {
31         if(a[i]!=i) {ans[i]=ans[((i-1)%a[i])+1];continue;}
32         cnt++;
33         j=i-1;
34         while(a[j]!=j)
35         {
36             j=(j-1)%a[j]+1;
37             hsh[ans[j+1]-'a']=cnt;
38         }
39         for(int k=1;k<=26;k++) if(hsh[k]!=cnt) {ans[i]=(char) 'a'+k;break;}
40     }
41     for(int i=1;i<=n;i++) printf("%c",ans[i]);
42 }
View Code

 

posted @ 2017-11-10 13:37  jack_yyc  阅读(231)  评论(0编辑  收藏  举报