【luogu P3809】【模板】后缀排序

【模板】后缀排序

题目链接:luogu P3809

题目大意

给你一个字符串,要你输出它每个后缀的字典序排序。

思路

这道题是 SA 的模板题。

相对别的比较好打。
(然后我打了一整天)

它主要是用基数排序的思想排序,再用倍增加以优化。

那怎么倍增呢?
你假设你已经处理了长度为 k 的,然后你要处理 k×2 的。
然后你知道了对于你要求的长度是 k×2 的,你是先按前面的 k 的排序,然后如果相同,再看后面 k 的排序。
那我们就可以知道如果前面的排序相同,那它组成新的排序一定是在连续的一段。

那我们就对于每一段,倒叙枚举后面的部分,然后从区间从后面开始放。
那如果它到没有后面部分的时候呢?
那就直接设后面的排名是 0,让它放在最前面。

那按这个方法,从 1 长度开始处理,你就可以得到最后要的 sai 数组了。

代码

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, m; int p; int sa[1000001], rak[1000001], tp[1000001], tax[1000001]; char c[1000001]; void paixu() {//基数排序 for (int i = 1; i <= m; i++) tax[i] = 0; for (int i = 1; i <= n; i++) tax[rak[i]]++; for (int i = 2; i <= m; i++) tax[i] += tax[i - 1]; for (int i = n; i >= 1; i--) sa[tax[rak[tp[i]]]--] = tp[i]; } int main() { scanf("%s", c + 1); n = strlen(c + 1); for (int i = 1; i <= n; i++) { rak[i] = c[i]; tp[i] = i; } m = 122; paixu(); for (int w = 1; w < n; w <<= 1) {//SA m = p; p = 0; for (int i = n - w + 1; i <= n; i++) tp[++p] = i; for (int i = 1; i <= n; i++) if (sa[i] > w) tp[++p] = sa[i] - w; paixu(); swap(tp, rak); p = 1; rak[sa[1]] = 1; for (int i = 2; i <= n; i++) if (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w]) rak[sa[i]] = p; else rak[sa[i]] = ++p; if (p == n) break; } for (int i = 1; i <= n; i++) printf("%d ", sa[i]); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P3809.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(63)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示