[JSOI2007]字符加密Cipher SA
[JSOI2007]字符加密Cipher
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 7859 Solved: 3410
[Submit][Status][Discuss]
Description
喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法
:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。例如下图,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0把它们按照字符串的大小排序:07JSOI 7JSOI0 I07JSO JSOI07
OI07JS SOI07J读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是
突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?
Input
输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。
Output
输出一行,为加密后的字符串。
Sample Input
JSOI07
Sample Output
I0O7SJ
HINT
对于100%的数据字符串的长度不超过100000。
题解:先将于2倍的然后构造后缀数组即可,
满足条件的是SA中<=n,的那些+n-1个点。
1 #include<cstring> 2 #include<cmath> 3 #include<cstdio> 4 #include<algorithm> 5 #include<iostream> 6 7 #define N 200007 8 using namespace std; 9 inline int read() 10 { 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 14 return x*f; 15 } 16 17 int n,k; 18 int s[N],sa[N],rk[N*2],A[N],zhi[N]; 19 int a[N],b[N],cnta[N],cntb[N],tsa[N],height[N]; 20 char ch[N]; 21 22 void Get_SA() 23 { 24 for (int i=1;i<=n;i++)cnta[i]=0; 25 for (int i=1;i<=n;i++)cnta[s[i]]++; 26 for (int i=1;i<=n;i++)cnta[i]+=cnta[i-1]; 27 for (int i=n;i>=1;i--)sa[cnta[s[i]]--]=i; 28 rk[sa[1]]=1; 29 for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]); 30 for (int i=1;rk[sa[n]]!=n;i<<=1) 31 { 32 for (int j=1;j<=n;j++)a[j]=rk[j],b[j]=rk[j+i]; 33 for (int j=0;j<=n;j++)cnta[j]=cntb[j]=0; 34 for (int j=1;j<=n;j++)cnta[a[j]]++,cntb[b[j]]++; 35 for (int j=1;j<=n;j++)cnta[j]+=cnta[j-1],cntb[j]+=cntb[j-1]; 36 for (int j=n;j>=1;j--)tsa[cntb[b[j]]--]=j; 37 for (int j=n;j>=1;j--)sa[cnta[a[tsa[j]]]--]=tsa[j]; 38 rk[sa[1]]=1; 39 for (int j=2;j<=n;j++) 40 rk[sa[j]]=rk[sa[j-1]]+(a[sa[j]]!=a[sa[j-1]]||b[sa[j]]!=b[sa[j-1]]); 41 } 42 } 43 int main() 44 { 45 scanf("%s",ch+1); 46 int len; 47 len=n=strlen(ch+1); 48 for (int i=1;i<=n;i++)A[i]=s[i]=(int)(ch[i]); 49 sort(A+1,A+len+1); 50 len=unique(A+1,A+len+1)-A-1; 51 for (int i=1;i<=len;i++)zhi[i]=A[i]; 52 for (int i=1;i<=n;i++)s[i+n]=s[i]=lower_bound(A+1,A+len+1,s[i])-A; 53 s[n+n]=0; 54 int num=n;n=2*n-1; 55 Get_SA(); 56 for (int i=1;i<=n;i++) 57 if (sa[i]<=num) putchar(char(zhi[s[sa[i]+num-1]])); 58 }