LG4051/BZOJ1031 「JSOI2007」字符加密 后缀数组
题解
发现这是一个环,根据经验,破环为链,于是字符环变为了字符串
之后对这个复制之后的字符串求后缀数组。
$len$代表原字符串长度,代表复制后的字符串长度
最后输出的时候,判断一下,如果$SA_i \le len$,则输出$str_i$。
Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define maxn 1000007 5 6 void read(int &x){ 7 x=0;char ch=1;int fh; 8 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); 9 if(ch=='-') fh=-1,ch=getchar(); 10 else fh=1; 11 while(ch>='0'&&ch<='9'){ 12 x=(x<<1)+(x<<3)+ch-'0'; 13 ch=getchar(); 14 } 15 x*=fh; 16 } 17 18 char s[maxn]; 19 int n,m,sa[maxn],x[maxn],y[maxn],ct[maxn]; 20 21 int chk(int x){ 22 return x>0?x:x+n; 23 } 24 25 void SA(){ 26 for(register int i=1;i<=n;i++) ct[x[i]=s[i]]++; 27 for(register int i=2;i<=m;i++) ct[i]+=ct[i-1]; 28 for(register int i=n;i>=1;i--) sa[ct[x[i]]--]=i; 29 for(register int k=1;k<=n;k<<=1){ 30 int tot=0; 31 for(register int i=n-k+1;i<=n;i++) y[++tot]=i; 32 for(register int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k; 33 for(register int i=1;i<=m;i++) ct[i]=0; 34 for(register int i=1;i<=n;i++) ct[x[i]]++; 35 for(register int i=1;i<=m;i++) ct[i]+=ct[i-1]; 36 for(register int i=n;i>=1;i--) sa[ct[x[y[i]]]--]=y[i],y[i]=0; 37 swap(x,y);x[sa[1]]=tot=1; 38 for(register int i=2;i<=n;i++) 39 if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=tot; 40 else x[sa[i]]=++tot; 41 if(tot==n) break; 42 m=tot; 43 } 44 } 45 46 int rnk[maxn]; 47 int let; 48 int main(){ 49 ios::sync_with_stdio(0); 50 cin>>(s+1);n=strlen(s+1);let=n; 51 for(register int i=n+1;i<=n*2;i++) s[i]=s[i-n]; 52 n*=2; 53 m=122;SA(); 54 for(register int i=1;i<=n;i++){ 55 rnk[sa[i]]=i; 56 } 57 for(register int i=1;i<=n;i++){ 58 if(sa[i]<=let) 59 cout<<s[sa[i]+let-1]; 60 } 61 cout<<endl; 62 return 0; 63 }