1031: [JSOI2007]字符加密Cipher
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 5240 Solved: 2164
[ 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。
Source
直接后缀数组强制乱搞……窝是n log^2 n的,反正能过便是。
#include "stdio.h"
#include "string.h"
#include "algorithm"
using namespace std;
const int L=100005;
char str[L<<1];
int len,l;
struct Node { int x,y,id;};
struct Ans { int rank,beg;};
int rank[L<<1];
int bucket[L<<1];
Node f[L<<1];
Ans ans[L];
bool cmp(const Node a,const Node b){
return a.x==b.x? a.y<b.y : a.x<b.x;
}
bool cmp0(const Ans a,const Ans b){
return a.rank<b.rank;
}
void Suffix_Array(){
int lth,i,j;
for (i=0;i<l;i++) bucket[(int)str[i]]++;
for (i=1,j=1;i<0xff;i++) if(bucket[i]) bucket[i]=j++;
for (i=0;i<l;i++) rank[i]=bucket[(int)str[i]];
for (lth=1;lth<l;lth*=2){
for (i=0;i<l;i++) f[i].x=rank[i],f[i].id=i,f[i].y=i<l-lth?rank[i+lth]:0;
sort(f,f+l,cmp); rank[f[0].id]=1;
for (i=1,j=1;i<l;i++){
if(f[i].x!=f[i-1].x||f[i].y!=f[i-1].y) ++j;
rank[f[i].id]=j;
}
}
}
int main(){
scanf("%s",str);
len=strlen(str);
int i;l=len<<1;
for (i=0;i<len;i++) str[i+len]=str[i];
Suffix_Array();
for (i=0;i<len;i++) ans[i].beg=i,ans[i].rank=rank[i];
sort(ans,ans+len,cmp0);
for (i=0;i<len;i++) putchar(str[ans[i].beg+len-1]);
return 0;
}