持续划水中……

  感觉BZOJ上AC人数多的基本都是一些模板题,也就是某些算法的裸题。这些题目mark一下到时候回来复习也是不错的选择。

Description

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

   

                JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0
  把它们按照字符串的大小排序:07JSOI 7JSOI0 I07JSO JSOI07 OI07JS SOI07J
  读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?

Input

  输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。

Output

  输出一行,为加密后的字符串。

Sample Input

  JSOI07

Sample Output

  I0O7SJ

HINT

  字符串的长度不超过100000。

Solution

  后缀数组裸题嘛,小C觉得没什么可说的。

  本质就是一个长度为2n字符串有n个长度为n的子串,将它们排序。

  不过在这里小C要好好讲一讲自己对于后缀数组O(nlogn)算法的理解。

  虽然一开始小C看这个算法时也是头皮发麻,但是仔细想想代码中的道理也是非常好理解的。

  后缀数组核心代码只有9行,其中4行预处理,1行倍增,4行正式处理,而且预处理部分和正式处理部分本质是相同的。

  具体参见小C代码后面的注释。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define MN 200005
#define MS 256
using namespace std;
int mp[MN],rk[][MN],sa[][MN];
char c[MN];
int n,bn,K,g; inline int read()
{
int n=,f=; char c=getchar();
while (c<'' || c>'') {if(c=='-')f=-; c=getchar();}
while (c>='' && c<='') {n=n*+c-''; c=getchar();}
return n*f;
} void work(int* SA,int* RK,int* sa,int *rk)
{
register int i;
//正式处理部分:前3行以rk为第一关键字求出SA,后一行无脑求RK。(注意顺序)
for (i=;i<=n;++i) mp[rk[sa[i]]]=i; //不用前缀和,直接根据串x在sa中的排名得到mp[rk[x]]的前缀和。
for (i=n;i;--i) if (sa[i]>K) SA[mp[rk[sa[i]-K]]--]=sa[i]-K;
//对于扩展后长度大于K的后缀x,利用后缀x+K在sa中的排名得到x在SA中的排名。
for (i=n-K+;i<=n;++i) SA[mp[rk[i]]--]=i;
//然后就只剩下扩展后长度小等于K的后缀x,排名一定比大于K的后缀小,所以后处理。
for (i=;i<=n;++i) RK[SA[i]]=RK[SA[i-]]+(rk[SA[i]]!=rk[SA[i-]] || rk[SA[i]+K]!=rk[SA[i-]+K]);
//无脑求RK,注意用到sa。
//为了执行效率的提高,通常在对后缀排序时,如果发现某次扩展后,所有后缀的rk都不相同,即可停止倍增。
} void prework()
{
register int i;
//预处理部分:前3行用基数排序求出sa[0],后1行无脑求rk[0]。
for (i=;i<=n;++i) ++mp[c[i]];
for (i=;i<MS;++i) mp[i]+=mp[i-];
for (i=;i<=n;++i) sa[][mp[c[i]]--]=i;
for (i=;i<=n;++i) rk[][sa[][i]]=rk[][sa[][i-]]+(c[sa[][i]]!=c[sa[][i-]]);
//注意求rk的时候要按照sa的顺序。
//倍增部分:g代表数组滚动,K是扩展前的大小,扩展一次后sa内的后缀长度变为K*2。
for (g=,K=;K<=bn;K<<=,g^=) work(sa[g^],rk[g^],sa[g],rk[g]);
//至于求height数组的话,只要记住height[rk[i]]>=height[rk[i-1]]这个性质就行了。
} int main()
{
register int i;
scanf("%s",c+); n=strlen(c+);
for (i=;i<=n;++i) c[n+i]=c[i];
bn=n; n<<=;
prework(); c[]=c[n];
for (i=;i<=n;++i) if (sa[g][i]<=bn) putchar(c[sa[g][i]-]);
}

Last Word

  本来后缀数组是不亚于LCT困扰小C的存在,现在发现理解了就不需要那样死记硬背了。

  最后吐槽一下BZOJ上各种病句连篇的题面,在Blog上贴这种东西尴尬癌都要犯了。

[BZOJ]1031 字符加密Cipher(JSOI2007)的更多相关文章

  1. BZOJ 1031 字符加密

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

  2. 【BZOJ】【1031】【JSOI2007】字符加密Cipher

    后缀数组 当年感觉好神的题现在好像变水了…… 题意其实有点蛋疼……一开始没看懂<_< 将原串复制一遍接在后面,用后缀数组求一下SA,那么SA<n的就是所找到的那n个字符串,然后把它们 ...

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

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

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

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

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

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

  6. BZOJ 1031 [JSOI2007]字符加密Cipher 后缀数组教程

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

  7. 1031: [JSOI2007]字符加密Cipher

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

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

    /*1031: [JSOI2007]字符加密Cipher Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4926 Solved: 2020[Submit ...

  9. [JSOI2007]字符加密Cipher

    bzoj 1031:[JSOI2007]字符加密Cipher Time Limit: 10 Sec  Memory Limit: 162 MB Description 喜欢钻研问题的JS同学,最近又迷 ...

随机推荐

  1. Storm概念讲解和工作原理介绍

    Strom的结构 Storm与传统关系型数据库     传统关系型数据库是先存后计算,而storm则是先算后存,甚至不存     传统关系型数据库很难部署实时计算,只能部署定时任务统计分析窗口数据   ...

  2. 51Nod P1100 斜率最大

    传送门: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1100 由于2 <= N <= 10000, 所以 ...

  3. bzoj千题计划251:bzoj3672: [Noi2014]购票

    http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...

  4. 函数式编程之foldLeftViaFoldRight

    问题来自 Scala 函数式编程 一书的习题, 让我很困扰, 感觉函数式编程有点神学的感觉.后面看懂之后, 又觉得函数式编程所提供的高阶抽象是多么的强大. 这个问题让我发呆了好久, 现在把自己形成的想 ...

  5. MSIL实用指南-一维数组的操作

    本篇讲解怎么生成和操作一维数组.各种数组类型创建的步骤是一样的,但是加载和保存步骤有所不同. 一.创建数组所有类型的一维数组创建都是一样的,分三步.1.加载数组长度2.生成指令 Newarr < ...

  6. KNN算法的代码实现

    # -*- coding: utf-8 -*-"""Created on Wed Mar 7 09:17:17 2018 @author: admin"&quo ...

  7. python构造一个freebuf新闻发送脚本

    前言: 放假学习完web漏洞后.想写一个脚本 然而自己菜无法像大佬们一样写出牛逼的东西 尝试写了,都以失败告终. 还有一个原因:上学时间不能及时看到,自己也比较懒.邮件能提醒自己. 需要安装的模块: ...

  8. 深度学习之 mnist 手写数字识别

    深度学习之 mnist 手写数字识别 开始学习深度学习,先来一个手写数字的程序 import numpy as np import os import codecs import torch from ...

  9. Linq 集合操作符 Except,Intersect,Union

    IList<string> s1 = new List<string>() { "One", "Two", "Three&qu ...

  10. react-native-image-picker 运用launchCamera直接调取摄像头的缺陷及修复

    在前几天用react-native进行android版本开发当中,用到了"react-native-image-picker"的插件:根据业务的需求:点击按钮-->直接调取摄 ...