后缀数组主要功能:

长度为n的字符串总共有n个后缀,求这n个后缀的字典序

实现方法:倍增+基数排序,过程就是下面那张表

求log(n)次rank数组,每次的rank数组都可以通过上次的rank数组得出

最后的rank就是答案,过程看起来简单,但代码实现挺难得!

Rank[]:rank[i]=p表示下标为i开头的字符串排第p个

Sa[]:Sa[i]=p表示排第i个的字符串是下标为p开头的字符串

cot[]:辅助数组,cot[i]=p表示当前rank数组中值小于等于i的数的个数

例如rank[]:{1,2,4,1,1,1,2,3},那么cot[1]==4,cor[2]==6,cot[3]==7,cot[4]==8

(或初始字符串中ASCLL码<=i的字符个数)

Temp[]:Temp[i]=p意思就是第二个数(图里y数组)中第i的小的是下标p上的数

参考博文:

http://www.cnblogs.com/shanchuan04/p/5324009.html

http://blog.csdn.net/yxuanwkeith/article/details/50636898

http://blog.csdn.net/qq_34731703/article/details/52934284

代码中有注释

1031: [JSOI2007]字符加密Cipher

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 7202  Solved: 3120
[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

题解:裸的后缀数组,因为是个环不是个后缀所以要将字符串复制一遍接在后面

然后就是模板

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
char str[200100];
int a[200100], Rank[200100], Temp[200100], cot[200100], Sa[200100];
int main(void)
{int n, i, m, p, k;while(scanf("%s", str+1)!=EOF){n = strlen(str+1);for(i=1;i<=n;i++){a[i] = a[i+n] = str[i];str[i+n] = str[i];}n *= 2, m = 128;memset(cot, 0, sizeof(cot));for(i=1;i<=n;i++){Rank[i] = a[i];cot[a[i]]++;}for(i=1;i<=m;i++)cot[i] += cot[i-1];           //  cot[i]表示ASCLL码小于等于i的字符个数for(i=n;i>=1;i--)Sa[cot[a[i]]--] = i;/*puts(str+1);for(i=1;i<=n;i++)printf("%d ", Sa[i]);                       //  第一次排序,输入ABAAB,输出结果为:printf("\n");                                    //  ABAABABAABfor(i=1;i<=n;i++)                              //  1 3 4 6 8 9 2 5 7 10printf("%d ", Rank[i]);                       //  97 98 97 97 98 97 98 97 97 98printf("\n");*/for(k=1;k<=n;k*=2){p = 0;for(i=n-k+1;i<=n;i++)         //下标在[n+1, n+k]范围内的字符是空字符,所以字典序肯定是最小的Temp[++p] = i;for(i=1;i<=n;i++)         //前k个字符因为不参与排序,后面所有字符自动向前面移动k位(下标-k){if(Sa[i]>k)Temp[++p] = Sa[i]-k;}/*printf("k=%d\nTemp: ", k);for(i=1;i<=n;i++)                     //  当k=1时,输出结果为:printf("%d ", Temp[i]);                //  10 2 3 5 7 8 1 4 6 9printf("\n");*/memset(cot, 0, sizeof(cot));for(i=1;i<=n;i++)                   /*这个时候,可以把rank当成新的a数组,之前的数组已经毫无意义*/cot[Rank[i]]++;for(i=1;i<=m;i++)cot[i] += cot[i-1];for(i=n;i>=1;i--)Sa[cot[Rank[Temp[i]]]--] = Temp[i];/* Temp[i]=p意思就是第二个数(图里y数组)中第i的大的是下标p上的数*/swap(Rank, Temp);p = 1;Rank[Sa[1]] = 1;         //求出当前的rank数组,在这里之前的rank数组就已经毫无意义了for(i=2;i<=n;i++){if(Temp[Sa[i-1]]==Temp[Sa[i]] && Temp[Sa[i-1]+k]==Temp[Sa[i]+k])Rank[Sa[i]] = p;elseRank[Sa[i]] = ++p;}m = p;/*printf("Rank: ");for(i=1;i<=n;i++)                 //  当k=1时,输出结果为:printf("%d ", Rank[i]);            //  2 4 1 2 4 2 4 1 2 3printf("\n");*/}n /= 2;for(i=1;i<=2*n;i++){if(Sa[i]>n)continue;printf("%c", str[Sa[i]+n-1]);}printf("\n");}
}

后缀数组(bzoj 1031: [JSOI2007]字符加密Cipher)相关推荐

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

    为什么我的后缀数组跑得这么慢... 把字符串复制一遍放在最后, 然后跑sa, 扫一遍就行了... --------------------------------------------------- ...

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

    题面 题目传送门 解法 后缀数组模板题吧-- 将字符串两倍,然后求一遍sa数组即可 时间复杂度:\(O(n\ log\ n)\) 代码 #include <bits/stdc++.h> # ...

  3. 【BZOJ】1031: [JSOI2007]字符加密Cipher(后缀数组)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1031 很容易想到这就是将字符串复制到自己末尾然后后缀数组搞出sa然后按区间输出即可. 然后换了下模板 ...

  4. BZOJ1031: [JSOI2007]字符加密Cipher

    1031: [JSOI2007]字符加密Cipher Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 7882  Solved: 3425 [Subm ...

  5. [bzoj1031][JSOI2007]字符加密Cipher

    1031: [JSOI2007]字符加密Cipher Time Limit: 10 Sec Memory Limit: 162 MB Submit: 4175 Solved: 1694 [Submit ...

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

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

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

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

  8. bzoj1031 [JSOI2007]字符加密 后缀数组改

    DA后缀数组构造的思想主要的就是倍增 即类似RMQ的双关键字排序 所以就可以用双关键字排序的方法来构造后缀数组 基数排序和快排都可以,鉴于是1e5,直接nlogn就够了 码: #include< ...

  9. [JSOI2007]字符加密

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

最新文章

  1. C#用 SendKyes 结合 Process 或 API FindWindow、SendMessage(PostMessage) 等控制外部程序
  2. 解决IDEA使用lombok注解无效,@Data不生效问题
  3. 《精通Nginx》——2.3 使用include文件
  4. 自定义Checkbox让复选框居中对于RadioButton同样适用
  5. phpize增加php模块
  6. CF451E-Devu and Flowers【组合计数,容斥】
  7. vbox虚拟机配置Redhat6.4本地yum源
  8. 利用处理程序错误***(下)
  9. 关于Myeclipse10的激活
  10. Servlet读取xml文件的配置参数
  11. css3多变形,CSS3 clip-path polygon图形构建与动画变换二三事
  12. linux用户态和内核态堆栈,Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
  13. 0.96寸OLED屏幕
  14. 你想成为什么样的人取决于你付出了多少?
  15. 巴西龟饲养日志----冬眠记录
  16. crontab 奇数时间定时执行
  17. 如何理解IT、OT、CT?边缘计算
  18. 笔记本电脑设备管理器中'符合USBxHCI的主机控制器'出现感叹号,所有的USB接口失灵--解决
  19. IC功能芯片的封装和包装经验
  20. 【Java】2022年团体程序设计天梯赛 L1 和 L2-042 题解

热门文章

  1. python入门经典100例-Python3经典100例(Python3入门习题) 含答案 doc版
  2. python处理excel表格-如何用python处理excel表格
  3. 语音识别系统_智能语音识别系统_第三方语音识别系统 - 云+社区 - 腾讯云
  4. linux的课程完全看不懂,学习Linux命令神器-看不懂直接给你解释
  5. python windows 消息通讯_如何使用python與windows中的事件/消息掛鈎
  6. mysql排序规则英文 数字_如何在MySQL中为日语设置模式排序规则
  7. axios的http拦截
  8. 开发中git的常用命令
  9. 开源安卓播放器:Dolphin Player 简单分析
  10. svm 文本分类 matlab,livsvm文本分类总结详解