题目链接

//输出ht见UOJ.35
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1e6+5; int n,tm[N],t1[N],t2[N],SA[N],rk[N],ht[N];
//SA[i]=j:排名为i的后缀开头的下标为j
//rk[i]=j:以下标i开头的后缀排名为j
//ht[i]:排名为i的后缀与排名为i-1的后缀的LCP长度
char s[N]; void Get_SA()
{
int *x=t1,*y=t2,limit=80;//首先对单个字符进行排序,limit最初就为字符集大小(就是不同字符的个数)
for(int i=0;i<n;++i) ++tm[x[i]=s[i]-'0'];
for(int i=1;i<limit;++i) tm[i]+=tm[i-1];
for(int i=n-1;~i;--i) SA[--tm[x[i]]]=i;//基数排序
//x[]相当于是rank值
for(int p=0,k=1;k<n;k<<=1,limit=p,p=0)//每次更新limit为p
{//p实际就是新一轮基数排序后 不同后缀的个数
//首先对第二关键字进行排序,y保存的就是对第二关键字排序后的结果
//这一过程可以直接用上次得到的SA[]求出
for(int i=n-k;i<n;++i) y[p++]=i;//第二关键字长度不为k,故先排
for(int i=0;i<n;++i) if(SA[i]>=k) y[p++]=SA[i]-k;//剩下的有完整第二关键字的(SA[i]>=k)按顺序,即SA[i]排,第一关键字的位置自然就是SA[i]-k
//对第一关键字的排序同对单个字符排序
for(int i=0;i<limit;++i) tm[i]=0;
for(int i=0;i<n;++i) ++tm[x[i]];//++tm[x[y[i]]];
for(int i=1;i<limit;++i) tm[i]+=tm[i-1];
for(int i=n-1;~i;--i) SA[--tm[x[y[i]]]]=y[i];//这个双关键字基数排序我现在也还是感觉好迷好nb=-= 并不很懂
//交换两个指针,因为要用到上一轮的rk(x),而y是没有用了
std::swap(x,y), x[SA[0]]=0, p=1;
//得到新的rank
for(int i=1;i<n;++i)
// x[SA[i]]=(y[SA[i-1]]==y[SA[i]]&&y[SA[i-1]+k]==y[SA[i]+k])?p-1:p++;//对于连续字符的字符串会WA //但是字符串下标从1开始(s[i]-'a'+1)就没事了...但注意要清空
if(y[SA[i-1]]==y[SA[i]]&&((y[SA[i-1]+k]==y[SA[i]+k]&&SA[i-1]+k<n&&SA[i]+k<n)||(SA[i-1]+k>=n&&SA[i]+k>=n))) x[SA[i]]=p-1;
else x[SA[i]]=p++;
if(p>=n) break;//不同字符串数已有n个,再继续倍增不会变了,break
}
}
void Calc_Ht()
{
for(int i=0;i<n;++i) rk[SA[i]]=i;//rk[]与SA[]互为反函数
// 有一个性质是:ht[rk[i]]>=ht[rk[i-1]]-1
// 因为去掉开头字符 后缀一大部分是相等的。比较明显
for(int j,k=0,i=0;i<n;ht[rk[i++]]=k)
{
if(!rk[i])// continue;//排名为0的字符串ht为0
{ht[0]=0;continue;}
j=SA[rk[i]-1], k?--k:0;//从k-1开始匹配(与上一名次字符串)
while(s[i+k]==s[j+k]&&i+k<n&&j+k<n) ++k;
}
} int main()
{
// freopen("sais.in","r",stdin);
// freopen("sais.out","w",stdout); scanf("%s",s),n=strlen(s);
Get_SA();
Calc_Ht();
for(int i=0;i<n;++i) printf("%d ",SA[i]+1);
putchar('\n');
for(int i=1;i<n;++i) printf("%d ",ht[i]); return 0;
}

洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记的更多相关文章

  1. 洛谷4455 [CQOI2018]社交网络 (有向图矩阵树定理)(学习笔记)

    sro_ptx_orz qwq算是一个套路的记录 对于一个有向图来说 如果你要求一个外向生成树的话,那么如果存在一个\(u\rightarrow v\)的边 那么\(a[u][v]--,a[v][v] ...

  2. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  3. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  4. 洛谷 3379 最近公共祖先(LCA 倍增)

    洛谷 3379 最近公共祖先(LCA 倍增) 题意分析 裸的板子题,但是注意这题n上限50w,我用的边表,所以要开到100w才能过,一开始re了两发,发现这个问题了. 代码总览 #include &l ...

  5. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  6. UOJ #35. 后缀排序[后缀数组详细整理]

    #35. 后缀排序 统计 描述 提交 自定义测试 这是一道模板题. 读入一个长度为 nn 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符 ...

  7. Uoj #35. 后缀排序(后缀数组)

    35. 后缀排序 统计 描述 提交 自定义测试 这是一道模板题. 读入一个长度为 nn 的由小写英文字母组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在 ...

  8. Codevs 1500 后缀排序(后缀数组)

    1500 后缀排序 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 天凯是MIT的新生.Prof. HandsomeG给了他一个 ...

  9. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

随机推荐

  1. UML和模式应用1: 面向对象的分析与设计

    1.基本术语说明 items note OOA/D  面向对象的分析与设计 UML 描述.构造和文档化系统制品的可视化语言 模式 问题解决方案的公式 2. 本书的主要内容 本书的主旨是对应用了UML和 ...

  2. win7下出现读不到移动硬盘的解决办法

    很多电脑会出现移动硬盘读不到,或者 读到部分盘的情况,那么下面我就为大家来一一解决这些情况: 方法一:    最常见的是硬盘供电不足导致 ,要么换一个硬盘盒子,要么给硬盘一个外加电源即可方法二:    ...

  3. 巧用CASE WHEN 验证用户登录信息

    最近逛博客园的时候偶然看到一个很巧妙的SQL,巧妙利用CASE WHEN 实现一个简单的 SQL 同时验证用户帐号是否存在.密码是否正确.晓菜鸟之前的做法都是根据用户名和密码一起验证,如果验证失败直接 ...

  4. (常用)time,datetime,random,shutil(zipfile,tarfile),sys模块

    a.time模块import time 时间分为三种形式1.时间戳 (时间秒数的表达形式, 从1970年开始)print(time.time())start_time=time.time()time. ...

  5. 利用pyecharts做地图数据展示

    首先, pip install pyecharts 为了地图上的数据能显示完全,加载好需要的城市地理坐标数据. pip install echarts-countries-pypkg pip inst ...

  6. Android 的网络编程

    android的网络编程分为2种:基于socket的,和基于http协议的. 基于socket的用法 服务器端: 先启动一个服务器端的socket     ServerSocket svr = new ...

  7. php 中使用include、require、include_once、require_once的区别

    在PHP中,我们经常会通过include.require.include_once.require_once来引用文件,都可以达到引用文件的目的,但他们之间又有哪些区别呢,接一下我们详细的介绍一下 i ...

  8. python 全栈开发,Day134(爬虫系列之第1章-requests模块)

    一.爬虫系列之第1章-requests模块 爬虫简介 概述 近年来,随着网络应用的逐渐扩展和深入,如何高效的获取网上数据成为了无数公司和个人的追求,在大数据时代,谁掌握了更多的数据,谁就可以获得更高的 ...

  9. JavaScrit全面总结

    前端技术的发展变化太快了,各种各样的框架.再变也离不开js.所以,在此把js的高级语法总结一遍.    js解析和执行包括:全局和函数 一:全局预处理 <script type="te ...

  10. Android使用帧动画内存溢出解决方法

    Android使用帧动画内存溢出解决方法https://blog.csdn.net/daitu_liang/article/details/52336015https://blog.csdn.net/ ...