字符串最小表示 后缀自动机 O(n)

把串复制一次,链接在后面之后,建立SAM,贪心地在SAM上转移,每次贪心地选择最小的字符,转移的长度为n时停止。

输出时由于要最靠前的,所以要在endpos集合中挑一个最小的,这个在slink_tree上递推一下就能轻松获得。

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. using namespace std;
  5. #define MAXL 10000
  6. #define MAXC 26
  7. int v[2*MAXL+10],__next[2*MAXL+10],first[2*MAXL+10],e;
  8. void AddEdge(int U,int V){
  9. v[++e]=V;
  10. __next[e]=first[U];
  11. first[U]=e;
  12. }
  13. char s[MAXL*2+10];//文本串
  14. int len/*文本串长度*/;
  15. struct SAM{
  16. int minendpos[2*MAXL+10];
  17. int n/*状态数0~n-1*/,maxlen[2*MAXL+10],minlen[2*MAXL+10],trans[2*MAXL+10][MAXC],slink[2*MAXL+10];
  18. void clear(){
  19. memset(maxlen,0,sizeof(maxlen));
  20. memset(minlen,0,sizeof(minlen));
  21. memset(trans,0,sizeof(trans));
  22. memset(slink,0,sizeof(slink));
  23. memset(minendpos,0x7f,sizeof(minendpos));
  24. n=0;
  25. }
  26. int new_state(int _maxlen,int _minlen,int _trans[],int _slink){
  27. maxlen[n]=_maxlen;
  28. minlen[n]=_minlen;
  29. for(int i=0;i<MAXC;++i){
  30. if(_trans==NULL){
  31. trans[n][i]=-1;
  32. }
  33. else{
  34. trans[n][i]=_trans[i];
  35. }
  36. }
  37. slink[n]=_slink;
  38. return n++;
  39. }
  40. int add_char(char ch,int u,int pos){
  41. if(u==-1){
  42. return new_state(0,0,NULL,-1);
  43. }
  44. int c=ch-'a';
  45. int z=new_state(maxlen[u]+1,-1,NULL,-1);
  46. minendpos[z]=pos;
  47. int v=u;
  48. while(v!=-1 && trans[v][c]==-1){
  49. trans[v][c]=z;
  50. v=slink[v];
  51. }
  52. if(v==-1){//最简单的情况,suffix-path(u->S)上都没有对应字符ch的转移
  53. minlen[z]=1;
  54. slink[z]=0;
  55. return z;
  56. }
  57. int x=trans[v][c];
  58. if(maxlen[v]+1==maxlen[x]){//较简单的情况,不用拆分x
  59. minlen[z]=maxlen[x]+1;
  60. slink[z]=x;
  61. return z;
  62. }
  63. int y=new_state(maxlen[v]+1,-1,trans[x],slink[x]);//最复杂的情况,拆分x
  64. slink[y]=slink[x];
  65. minlen[x]=maxlen[y]+1;
  66. slink[x]=y;
  67. minlen[z]=maxlen[y]+1;
  68. slink[z]=y;
  69. int w=v;
  70. while(w!=-1 && trans[w][c]==x){
  71. trans[w][c]=y;
  72. w=slink[w];
  73. }
  74. minlen[y]=maxlen[slink[y]]+1;
  75. return z;
  76. }
  77. void dfs(int U){
  78. for(int i=first[U];i;i=__next[i]){
  79. dfs(v[i]);
  80. minendpos[U]=min(minendpos[U],minendpos[v[i]]);
  81. }
  82. }
  83. void work_slink_tree(){
  84. for(int i=1;i<n;++i){
  85. AddEdge(slink[i],i);
  86. }
  87. dfs(0);
  88. }
  89. }sam;
  90. int T;
  91. int main(){
  92. // freopen("poj1509.in","r",stdin);
  93. scanf("%d",&T);
  94. for(;T;--T){
  95. sam.clear();
  96. scanf("%s",s);
  97. len=strlen(s);
  98. for(int i=0;i<len-1;++i){
  99. s[i+len]=s[i];
  100. }
  101. int U=sam.add_char(0,-1,0);
  102. for(int i=0;i<len*2-1;++i){
  103. U=sam.add_char(s[i],U,i);
  104. }
  105. U=0;
  106. for(int i=0;i<len;++i){
  107. for(int j=0;j<MAXC;++j){
  108. if(sam.trans[U][j]!=-1){
  109. U=sam.trans[U][j];
  110. break;
  111. }
  112. }
  113. }
  114. printf("%d\n",sam.minendpos[U]-len+2);
  115. }
  116. return 0;
  117. }

【后缀自动机】poj1509 Glass Beads的更多相关文章

  1. POJ1509 Glass Beads(最小表示法 后缀自动机)

    Time Limit: 3000MS   Memory Limit: 10000K Total Submissions: 4901   Accepted: 2765 Description Once ...

  2. POJ1509 Glass Beads

    Glass Beads Time Limit: 3000MS   Memory Limit: 10000K Total Submissions: 4314   Accepted: 2448 Descr ...

  3. POJ1509 Glass Beads [后缀自动机]

    题意: 给一个字符串S,每次可以将它的第一个字符移到最后面,求这样能得到的字典序最小的字符串.输出开始下标 练习SAM第一题! SS构造SAM,然后从开始尽量走最小走n步就可以啦 什么?开始位置?!R ...

  4. POJ1509 Glass Beads 【后缀自动机】

    题目分析: 模板练手.看最长能走多远. 代码: #include<iostream> #include<cstdio> #include<cstdlib> #inc ...

  5. [POJ1509]Glass Beads 后缀自动机 最小循环串

    题目链接:http://poj.org/problem?id=1509 题目意思就是求循环字符串的最小表示. 我们用字符串S+S建立SAM,然后从root开始走n步,每次尽量选最小的. 由于 SAM ...

  6. [poj1509]Glass Beads(最小表示法)

    题目大意:求循环同构的字符串的最小字典序. 解题关键:最小表示法模板题. #include<cstdio> #include<cstring> #include<algo ...

  7. 【POJ1509】Glass Beads 【后缀自动机】

    题意 给出一个字符串,求它的最小表示法. 分析 这个题当然可以用最小表示法做啦!但是我是为了学后缀自动机鸭! 我们把这个字符串长度乘二,然后建SAM,然后在SAM上每次跑最小的那个字母,找出长度为n的 ...

  8. UVA 719 / POJ 1509 Glass Beads (最小表示法/后缀自动机)

    题目大意: 给出一个长度为N的字符串,求其字典序最小的循环同构. N<=10W. 算法讨论: 算法一.最小表示法.定义题. 算法二.后缀自动机. Codes: #include <iost ...

  9. POJ 1509 Glass Beads 后缀自动机 模板 字符串的最小表示

    http://poj.org/problem?id=1509 后缀自动机其实就是一个压缩储存空间时间(对节点重复利用)的储存所有一个字符串所有子串的trie树,如果想不起来长什么样子可以百度一下找个图 ...

随机推荐

  1. 20151024_004_C#基础知识(C#中的访问修饰符,继承,new关键字,里氏转换,is 和 as,多态,序列化与反序列化)

    1:C#中的访问修饰符 public: 公共成员,完全公开,没有访问限制. private: 私有的,只能在当前类的内部访问. protected: 受保护的,只能在当前类的内部以及该类的子类中访问. ...

  2. webstorm vue环境设置

    1. 首先安装vue插件,安装方法: setting  -->  plugin  ,点击plugin,在内容部分的左侧输入框输入vue,会出现两个关于vue的插件,点击安装即可.安装完成后,就可 ...

  3. js_md5加密和base64的加密解密

    1.最近有些人在爬我们公司的数据,然有了这个md5加密的小需求.为什么叫小需求呢?嗯,之前没做过,会以为很复杂. 其实,是想多了. 2.前端md5加密,其实也并不是安全的,因为代码是可见的.也就是说, ...

  4. C++学习之路(六):实现一个String类

    直接贴代码吧,这段时间准备面试也正好练习了一下. class String { public: String(const char *str = ""); ~String(void ...

  5. C++之容器

    容器,迭代器与容器适配器 所谓容器,即是将最常运用的一些数据结构(data structures)用类模板实现出来,用于容纳特定类型的对象.根据数据在容器中排列的特性,容器可概分为序列式(sequen ...

  6. perl_nc.pl

    #!/usr/bin/perl use strict; use IO::Socket; use IO::Select; use Getopt::Std; my %option;getopts('lp: ...

  7. python的时间和日期--time、datetime应用

    time >>> import time >>> time.localtime() #以time.struct_time类型,打印本地时间 time.struct_ ...

  8. pypcap 安装

    1.下载winpcap开发包 https://www.winpcap.org/devel.htm 下载https://github.com/pynetwork/pypcap/releases最新发布的 ...

  9. linux命令(43):cal命令

    cal命令可以用来显示公历(阳历)日历.公历是现在国际通用的历法,又称格列历,通称阳历.“阳历”又名“太阳历”,系以地球绕行太阳一周为一年,为西方各国所通用,故又名“西历”. 1.命令格式: cal  ...

  10. jpa缓存导致无法查询到更新后的数据&android出现ANR的一个解决办法

    1. 向服务器更新记录后查询,始终查询不到更新后的信息 只能查到更新之前的,马上推断出是缓存的问题.网上搜索一番,将问题定位为jpa缓存,我们要设置jpa查询时不从缓存中取,直接从数据库中取,这样便能 ...