[JSOI2007]字符加密Cipher
[JSOI2007]字符加密Cipher
题目
喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。例如下图,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0把它们按照字符串的大小排序:07JSOI 7JSOI0 I07JSO JSOI07 OI07JS SOI07J读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?INPUT
输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。
OUTPUT
输出一行,为加密后的字符串。
SAMPLE
INPUT
JSOI07
OUTPUT
I0O7SJ
解题报告
第一道不是板子题的$SA$(这tm不是板子题?)
首先,因为这玩意是个环,所以我们把串翻倍
然后跑一遍板子,求出$SA$
接下来就是怎么用的问题了
我们知道,$SA[i]$表示第$i$个后缀的首位置下标,所以我们可以找到对应每个排名的下标,对应输出相应字符即可
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 char ch[100005],s[200010]; 6 int len; 7 int n,m; 8 int t1[200010],t2[200010],t3[200010],buc[200010]; 9 int sa[200010],rank[200010]; 10 inline void Suffix(){ 11 int i,j,k(0),p(0),*x(t1),*y(t2),*t; 12 for(i=0;i<=m;++i)buc[i]=0; 13 for(i=1;i<=n;++i)++buc[x[i]=s[i]]; 14 for(i=1;i<=m;++i)buc[i]+=buc[i-1]; 15 for(i=n;i>=1;--i)sa[buc[x[i]]--]=i; 16 for(j=1;p<n;j<<=1,m=p){ 17 for(p=0,i=n-j+1;i<=n;++i)y[++p]=i; 18 for(i=1;i<=n;++i) 19 if(sa[i]-j>0) 20 y[++p]=sa[i]-j; 21 for(i=0;i<=m;++i)buc[i]=0; 22 for(i=1;i<=n;++i)t3[i]=x[y[i]]; 23 for(i=1;i<=n;++i)++buc[t3[i]]; 24 for(i=1;i<=m;++i)buc[i]+=buc[i-1]; 25 for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i]; 26 for(t=x,x=y,y=t,p=1,x[sa[1]]=1,i=2;i<=n;++i) 27 x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p; 28 } 29 for(i=1;i<=n;++i)rank[sa[i]]=i; 30 } 31 inline char get(int x){ 32 int tmp(sa[x]);//cout<<x<<" "<<tmp<<endl; 33 tmp=tmp+len-1; 34 if(tmp>n) 35 tmp-=len; 36 return s[tmp]; 37 } 38 int main(){ 39 scanf("%s",ch); 40 len=strlen(ch); 41 for(int i=1;i<=len;++i) 42 s[i]=ch[i-1]; 43 for(int i=1;i<=len;++i) 44 s[len+i]=ch[i-1]; 45 n=len<<1; 46 m=130; 47 Suffix(); 48 for(int i=2;i<=n;i+=2) 49 putchar(get(i)); 50 }