LG4051/BZOJ1031 「JSOI2007」字符加密 后缀数组

问题描述

BZOJ1031

LG4051


题解

发现这是一个环,根据经验,破环为链,于是字符环变为了字符串

之后对这个复制之后的字符串求后缀数组。

$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 }
posted @ 2019-09-06 22:57  expect2004  阅读(136)  评论(0编辑  收藏  举报