[JSOI2007] [BZOJ1031] 字符加密Cipher - 后缀数组

1031: [JSOI2007]字符加密Cipher

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值