1031: [JSOI2007]字符加密Cipher

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。


  感人啊。这是第一道后缀数组的题目。早在高一寒假期间,就有学长讲过后缀数组(但当时内心当然崩溃欲绝)。后来,在高一下期,我也曾致力学习后缀数组。当时是有成效的,至少当时理解了倍增法,会解height数组,还会解一些经典题目。但时过境迁,一切都不一样了。后来,在沈阳又有学长讲授,但是也没有太大的收获(准确的说,这位一本爷的后缀数组还没有我好)。

  然后,然后,我就忘了。

  看来事情就是这样了。如果不练习,那很快就会忘记。

  我们来普及一下吧。其实后缀数组,sa就是求排名第i的是谁,rank就是求i排名第几,很明显sa与rank互为反函数。也就是说,sa[rank[i]]=i,排名第rank[i](i的排名)的是i。rank[sa[i]]=i,sa[i](排名第i的是谁)排名第i。这是很有趣的。

  而sa其实对应了一种有趣的树:后缀树。什么是后缀树呢?其实就是把一个串S的所有后缀串都插入一个trie,这个trie很明显与该串所有子串插入后形成的trie等价(每一个子串都是一个后缀的前缀)。但是,这样的树有O(n^2)个节点,想要实际建出明显不可能。

  不能实际建出,于是有人就像要把这棵树压缩且不改变效果,于是有了O(n)的后缀自动机。当然,"实用"化后的后缀树也压缩过。但是,后缀树在OI中的应用并不广泛。

  但是,我们也可以观察,发现可以把后缀树的末梢对应后缀从左往右写出,形成了一个数组,学名suffix_array,简称sa。当然,完整的模拟还需要一个height数组,意为sa[i-1]与sa[i]的最长公共前缀(一个不等式就可解决:height[rank[i]]>=height[rank[i-1]]-1,画图易证)。

  如何求sa和rank呢?我们通常有2种方法,一种人称倍增O(nlog n),另一种人称DC3 O(n)。DC3常数大得起飞,通常人们都写倍增。

  倍增是什么?还是建议去看一看罗穗骞

  很有道理。1,2,4,8,16,32……最多log n次排序即可达到目标。但是一次排序怎么能是O(nlg n)的呢?于是通常会用基数排序,基数排序即是从优先级低的位到优先级高的位,对于每一位进行计数排序,中间保证是稳定的。这里排序的稳定性是指按优先级高的位排序过后,若优先级高的位相同则优先级低的位相对顺序不变。

  计数排序即是人们俗称的桶排序(但是《算导》上说这是两种算法……迷……),把值扔到桶中,统计前缀和,然后得出排名。

  假设给n个数基数排序,是BASE“进制”的,这些数值域为W,那么需要进行logBASEW次计数排序。总的时间复杂度为max(n,BASE)*logBASEW,而空间复杂度为max(n,BASE)。

  发一波代码吧:

  好的,我们已经会计数排序和基数排序了。我们发现,在每一次倍增时,第二关键字可以直接处理,而第一关键字需要在此之上进行一次计数排序。然后,把新的rank处理出来,因为对于每一次倍增,实时性的rank是排序所必须的value。

  此处有一个小优化,一旦出现了多于lens个排名,那么排序已经结束,就可以退出了。

  这是我此题的代码(也是后缀数组的模板这里小小提一下,注意一个地方的顺序,刘汝佳在此处是错的):

 /**************************************************************
Problem: 1031
User: Doggu
Language: C++
Result: Accepted
Time:1032 ms
Memory:4140 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#include <algorithm>
const int S = ;
int bucket[S], rank[S], half[S], sa[S];
char ss[S];
void counting_sort(int range,int lens) {//In suffix_array, rank is the value, half is the radix, counting_sort and count_sort are radix sort
for( int i = ; i < range; i++ ) bucket[i]=;//clear
for( int i = ; i < lens; i++ ) bucket[rank[half[i]]]++;
for( int i = ; i < range; i++ ) bucket[i]+=bucket[i-];
for( int i =lens-; i>=; i-- ) sa[--bucket[rank[half[i]]]]=half[i];//half-->sa who to the what rank
}
bool cmp(int i,int k,int lens) {return half[sa[i]]==half[sa[i-]]&&(sa[i]+k<lens?half[sa[i]+k]:'\0')==(sa[i-]+k<lens?half[sa[i-]+k]:'\0');}
void calculate(int range) {
int lens = strlen(ss);
for( int i = ; i < lens; i++ ) rank[i]=ss[i], half[i]=i;
counting_sort(range,lens);
for( int k = ; k <= lens; k<<= ) {
int p=;for( int i = lens-1; i >= lens-k; i-- ) half[p++]=i;
for( int i = ; i < lens; i++ ) if(sa[i]>=k) half[p++]=sa[i]-k;
counting_sort(range,lens);std::swap(rank,half);range=;rank[sa[]]=;
for( int i = ; i < lens; i++ ) rank[sa[i]]=cmp(i,k,lens)?range-:range++;
if(range>=lens) break;
}
}
int main() {
scanf("%s",ss);
int lens = strlen(ss);
for( int i = lens; i < *lens; i++ ) ss[i]=ss[i-lens];ss[*lens]='\0';
calculate();
for( int i = ; i < *lens; i++ ) if(sa[i]<lens) printf("%c",ss[sa[i]+lens-]);printf("\n");
return ;
}

BZOJ 1031 [JSOI2007]字符加密Cipher 后缀数组教程的更多相关文章

  1. BZOJ 1031 [JSOI2007]字符加密Cipher | 后缀数组模板题

    BZOJ 1031 [JSOI2007]字符加密Cipher | 后缀数组模板题 将字符串复制一遍接在原串后面,然后后缀排序即可. #include <cmath> #include &l ...

  2. BZOJ 1031: [JSOI2007]字符加密Cipher 后缀数组

    1031: [JSOI2007]字符加密Cipher Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6014  Solved: 2503[Submit ...

  3. bzoj 1031 [JSOI2007]字符加密Cipher 后缀数组模板

    题目链接 题目描述 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作: ...

  4. bzoj 1031: [JSOI2007]字符加密Cipher 後綴數組模板題

    1031: [JSOI2007]字符加密Cipher Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3157  Solved: 1233[Submit ...

  5. 【BZOJ1031】[JSOI2007]字符加密Cipher 后缀数组

    [BZOJ1031][JSOI2007]字符加密Cipher Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的 ...

  6. 【BZOJ 1031】[JSOI2007]字符加密Cipher(后缀数组模板)

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1031 [题意] [题解] 后缀数组模板题; 把整个字符串扩大一倍. 即长度乘2 然后搞 ...

  7. 1031. [JSOI2007]字符加密【后缀数组】

    Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作 ...

  8. bzoj 1031 [JSOI2007]字符加密Cipher

    求出来后缀数组的rank就行了,不会可以去看集训队论文. #include<iostream> #include<cstdio> #include<cstring> ...

  9. bzoj 1031: [JSOI2007]字符加密Cipher【后缀数组】

    算是SA的裸题了 把串复制一遍接在原串后面,然后求SA,然后按着SA的顺序输出尾字符即可 #include<iostream> #include<cstdio> #includ ...

随机推荐

  1. Maltego——互联网情报聚合工具初探(转)

    有时候你可曾想过,从一个Email,或者Twitter,或是网站,甚至姓名等等,能找到一个人千丝万缕的联系,并把这些联系整合,利用起来?Maltego就是这样一款优秀而强大的工具.Maltego允许从 ...

  2. 20155233 《网络对抗》 Exp8 Web基础

    实验内容 Web前端HTML Web前端javascipt Web后端:MySQL基础:正常安装.启动MySQL,建库.创建用户.修改密码.建表 Web后端:编写PHP网页,连接数据库,进行用户认证 ...

  3. [Python]-pip-ReadTimeoutError: Read timed out 问题

    问题描述 就是在安装Python包的时候,由于时间太长引起的超时问题 问题解决 第一个办法是更改源地址:在 ~/.pip/ 下创建文件 pip.conf(如果还没有的话), 模版如下: [global ...

  4. WPF编程,窗口保持上次关闭时的大小与位置。

    原文:WPF编程,窗口保持上次关闭时的大小与位置. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/details/8 ...

  5. Codeforces 950D A Leapfrog in the Array (思维)

    题目链接:A Leapfrog in the Array 题意:给出1-n的n个数,从小到大每隔一个位置放一个数.现在从大到小把数往前移动,每次把最右边的数移动最靠右边的空格处直到n个数都在前n个位置 ...

  6. JVM技术周报第2期

    JVM技术周报第2期 JVM技术周报分享JVM技术交流群的讨论内容,由群内成员整理归纳而成.如果你有兴趣入群讨论,请关注「Java技术精选」公众号,通过右下角菜单「入群交流」加我好友,获取入群详情. ...

  7. c语言连接mysql数据库的实现方法

    C语言连接mysql数据库,需要相应的头文件和lib文件,如果你安装Mysql数据库,会在安装目录下找到这些库文件,如果没有安装,也可以在网上找到 我这里也有一份网上找到的:/201205/other ...

  8. 让docker中的mysql启动时自动执行sql文件

    本文提要 本文目的不仅仅是创建一个MySQL的镜像,而是在其基础上再实现启动过程中自动导入数据及数据库用户的权限设置,并且在新创建出来的容器里自动启动MySQL服务接受外部连接,主要是通过Docker ...

  9. 转 Git 常用命令大全

    一. Git 常用命令速查 git branch 查看本地所有分支 git status 查看当前状态  git commit 提交  git branch -a 查看所有的分支 git branch ...

  10. C语言 -- 字符串详解

    字符串是一种非常重要的数据类型,但是C语言不存在显式的字符串类型,C语言中的字符串都以字符串常量的形式出现或存储在字符数组中.同时,C 语言提供了一系列库函数来对操作字符串,这些库函数都包含在头文件 ...