[BZOJ 1031] [JSOI2007] 字符加密Cipher
1031: [JSOI2007]字符加密Cipher
Time Limit: 10 SecDescription
喜欢钻研问题的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。
【题解】
稍微入门了后缀数组,这是基础题。
然而NOIP并不考,我得先备战NOIP TAT
1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cstdio> 6 #define N 220000 7 using namespace std; 8 #define rep(i,a,b) for(i=a;i<b;++i) 9 #define drep(i,a,b) for(i=a;i>=b;--i) 10 using namespace std; 11 int p[N],wc[N],wv[N],wa[N],wb[N],rank[N],sa[N]; 12 char s[N]; 13 inline bool cmp(int *r,int a,int b,int l) { 14 return r[a]==r[b]&&r[a+l]==r[b+l]; 15 } 16 inline void tate(int *x,int *y,char *r,int n,int m,bool opt) { 17 int i; 18 rep(i,0,m) wc[i]=0; 19 rep(i,0,n) wc[opt?(x[i]=r[i]):wv[i]]++; 20 rep(i,1,m) wc[i]+=wc[i-1]; 21 drep(i,n-1,0) sa[--wc[opt?x[i]:wv[i]]]=opt?i:y[i]; 22 } 23 void f(char *r,int *sa,int n,int m) { 24 int i,j,p,*x=wa,*y=wb,*t; 25 tate(x,y,r,n,m,1); 26 for (j=1,p=1;p<n;j<<=1,m=p) { 27 p=0; 28 rep(i,n-j,n) y[p++]=i; 29 rep(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j; 30 rep(i,0,n) wv[i]=x[y[i]]; 31 tate(x,y,r,n,m,0); 32 for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;++i) 33 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 34 } 35 } 36 int main() { 37 scanf("%s",s); 38 int slen=strlen(s); 39 int n=slen*2; 40 for(int i=0;i<slen;i++) s[slen+i]=s[i]; 41 s[n-1]=0; 42 f(s,sa,n,300); 43 for(int i=0;i<n;i++) rank[sa[i]]=i; 44 for(int i=0;i<slen;i++) p[rank[i]]=s[i+slen-1]; 45 for(int i=0;i<n;i++) if(p[i]) printf("%c",p[i]); 46 return 0; 47 }
这篇文章由TonyFang发布。
所有解释权归TonyFang所有。
Mailto: tony-fang@map-le.net