• P3809 【模板】后缀排序


    读入一个长度为  n的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 1 到 n 。

    摘自:

    https://xminh.github.io/2018/02/27/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84-%E6%9C%80%E8%AF%A6%E7%BB%86(maybe)%E8%AE%B2%E8%A7%A3.html

    工具:

    1.基数排序 2. 倍增
    (此题不讨论lcp)

    中心思想:
    从1~n每个位置,按取的关键字个数(2^0,2^1,...,2^k倍增)来基数排序,直到排序没有重复为止。

    tot//每次排序后可分成多少不同组
    s[]//存原数组
    cnt[]//桶计数
    x[]//按第一关键字排序的下表位置
    y[]//按第二关键字排序的下标位置
    sa[]//记录每次排序后真正的下标位置

    上代码:

    int get_sa(){
    For(i,1,n)cnt[x[i]=s[i]]++;
    For(i,2,122)cnt[i]+=cnt[i-1];//122是z的ascii码
    FFor(i,n,1)sa[cnt[x[i]]--]=i;
    //上面一坨基数排序处理2^0
    for(int k=1;k<=n;k<<=1){
    int num=0;
    For(i,n-k+1,n)y[++num]=i;//i>=n-k+1说明下一位关键字位数不够,需要补零,既然补零那么一定最小,所以先加入队列
    For(i,1,n)if(sa[i]>=k+1)y[++num]=sa[i]-k;//如果sa[i]>=k+1,说明sa[i]可以成为别人的下一位关键字,那么把它对应的那个别人加进来
    me(cnt,0);//剩下的数继续走基数排序流程
    For(i,1,n)cnt[x[i]]++;
    For(i,2,tot)cnt[i]+=cnt[i-1];
    FFor(i,n,1)sa[cnt[x[y[i]]]--]=y[i],y[i]=0;
    swap(x,y);//因为要x的数组内容当做下一轮循环的第一关键字,且接下来更新时需要用到旧数组,所以用y顶替下
    x[sa[1]]=1;
    num=1;
    For(i,2,n)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num);//第一第二关键字合并起来后再排序
    if(num==n)break;
    tot=num;
    }
    For(i,1,n)cout<<sa[i]<<" ";
    }
  • 相关阅读:
    python 一
    opengl 正方体+模拟视角旋转
    MFC窗口实现最小化到托盘 右键菜单和还原
    C++获取当前机器内网IP地址
    ubuntu vim终端编辑命令
    整理网站优化(SEO)的方案
    c++函数声明的位置对函数重载的影响
    lua调用dll demo
    一、智能指针及线程同步总结------linux多线程服务端编程
    vscode remote wsl 的NoPermissions permission denied问题
  • 原文地址:https://www.cnblogs.com/planche/p/9418948.html
Copyright © 2020-2023  润新知