[BZOJ1031][JSOI2007]字符加密Cipher 解题报告
Description
喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。例如下图,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0 把它们按照字符串的大小排序: 07JSOI 7JSOI0 I07JSO JSOI07 OI07JS SOI07J 读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?
这道题好像也做了挺久...一个半小时吧
首先题目很亲切 总感觉去年暑假在镇中有过类似的题 但是那道题好像有神奇的O(n)做法
其实问题可以转化为将字符串及其循环以后的n-1个串从小到大排序,然后输出字符串首位的前一位字符
我们要解决字符串及其循环以后一共n个串的排序
我用后缀数组解决
我们可以直接用后缀数组处理出1 << (trunc(ln(n)/ln(2)))长度的排序
将后缀处理成子串的方法就在原串后面再接一次
然后再类似于倍增一点点将剩下的长度加入
实现方法类似于后缀数组 几个细节改动一下
但是由于要用到中间的数据,所以sa和rank数组要在每一次之后保留不能重复利用
还是一道非常不错的题呢^
1 program bzoj1031; 2 const maxn=200010; 3 var i,x,n:longint; 4 ss:ansistring; 5 a,s,tmp,rk,sa2:array[-1..maxn]of longint; 6 rank,sa:array[-1..20,-1..maxn]of longint; 7 8 function max(a,b:longint):longint; 9 begin 10 if a>b then exit(a) else exit(b); 11 end; 12 13 procedure Suffix_Array; 14 var i,j,k,p,v0,v00,v01,v1,size:longint; 15 begin 16 size:=256; 17 for i:=0 to n-1 do rank[0,i]:=a[i]; 18 for i:=0 to size-1 do s[i]:=0; 19 for i:=0 to n-1 do inc(s[rank[0,i]]); 20 for i:=1 to size-1 do inc(s[i],s[i-1]); 21 for i:=n-1 downto 0 do 22 begin 23 dec(s[rank[0,i]]); 24 sa[0,s[rank[0,i]]]:=i; 25 end; 26 j:=1;k:=1; 27 size:=n; 28 while j<=n >> 1 do 29 begin 30 p:=0; 31 for i:=n-j to n-1 do 32 begin 33 tmp[p]:=i; 34 inc(p); 35 end; 36 for i:=0 to n-1 do if sa[k-1,i]-j>=0 then 37 begin 38 tmp[p]:=sa[k-1,i]-j; 39 inc(p); 40 end; 41 for i:=0 to size-1 do s[i]:=0; 42 for i:=0 to n-1 do inc(s[rank[k-1,i]]); 43 for i:=1 to size-1 do inc(s[i],s[i-1]); 44 for i:=n-1 downto 0 do 45 begin 46 dec(s[rank[k-1,tmp[i]]]); 47 sa[k,s[rank[k-1,tmp[i]]]]:=tmp[i]; 48 end; 49 p:=0;rank[k,sa[k,0]]:=0; 50 for i:=1 to n-1 do 51 begin 52 v0:=sa[k,i-1];v1:=sa[k,i]; 53 if v0+j<n then v00:=rank[k-1,v0+j] else v00:=-1; 54 if v1+j<n then v01:=rank[k-1,v1+j] else v01:=-1; 55 if (rank[k-1,v0]=rank[k-1,v1])and(v00=v01) then rank[k,sa[k,i]]:=p else 56 begin 57 inc(p); 58 rank[k,sa[k,i]]:=p; 59 60 end; 61 end; 62 j:=j << 1;inc(k); 63 end; 64 end; 65 66 procedure solve; 67 var i,j,k,p,x,rec,v0,v1,v00,v01,size:longint; 68 begin 69 x:=trunc(ln(n >> 1)/ln(2)); 70 size:=max(256,n); 71 for i:=0 to n-1 do rk[i]:=rank[x,i]; 72 for i:=0 to size-1 do s[i]:=0; 73 for i:=0 to n-1 do inc(s[rk[i]]); 74 for i:=1 to size-1 do inc(s[i],s[i-1]); 75 for i:=n-1 downto 0 do 76 begin 77 dec(s[rk[i]]); 78 sa2[s[rk[i]]]:=i; 79 end; 80 rec:=n >> 1-1 << x; 81 while rec<>0 do 82 begin 83 x:=trunc(ln(rec)/ln(2)); 84 p:=0; 85 for i:=n-1 << x to n-1 do 86 begin 87 tmp[p]:=i; 88 inc(p); 89 end; 90 for i:=0 to n-1 do if sa[x,i]-1 << x>=0 then 91 begin 92 tmp[p]:=sa[x,i]-1 << x; 93 inc(p); 94 end; 95 for i:=0 to size-1 do s[i]:=0; 96 for i:=0 to n-1 do inc(s[rk[i]]); 97 for i:=1 to size-1 do inc(s[i],s[i-1]); 98 for i:=0 to n-1 do 99 begin 100 dec(s[rk[tmp[i]]]); 101 sa2[s[rk[tmp[i]]]]:=tmp[i]; 102 end; 103 p:=0;tmp[sa2[0]]:=0; 104 for i:=1 to n-1 do 105 begin 106 v0:=sa2[i-1];v1:=sa2[i]; 107 if v0+1 << x<n then v00:=rank[x,v0+1 << x] else v00:=-1; 108 if v1+1 << x<n then v01:=rank[x,v1+1 << x] else v01:=-1; 109 if (rk[v0]=rk[v1])and(v00=v01) then tmp[sa2[i]]:=p else 110 begin 111 inc(p); 112 tmp[sa2[i]]:=p; 113 end; 114 end; 115 for i:=0 to n-1 do rk[i]:=tmp[i]; 116 dec(rec,1 << x); 117 end; 118 end; 119 120 begin 121 readln(ss);n:=length(ss); 122 for i:=0 to n-1 do a[i]:=ord(ss[i+1]); 123 for i:=n to 2*n-1 do a[i]:=a[i-n]; 124 n:=n*2; 125 Suffix_Array; 126 solve; 127 for i:=0 to n-1 do if sa2[i]<(n >> 1) then 128 begin 129 x:=sa2[i]-1; 130 if x=-1 then x:=n >> 1-1; 131 write(ss[x+1]); 132 end; 133 end.