zoukankan      html  css  js  c++  java
  • POJ 1509 最小表示法/后缀自动机

    题意:

    给你一个字符串的环,求从那个位置起字符串的字典序最小。

    题解:

    最小表示法。

    论文链接

    View Code
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 #define N 20200
     8 //求最小循环同构串起点 
     9 using namespace std;
    10 
    11 char str[N];
    12 int len;
    13 
    14 inline int go()
    15 {
    16     scanf("%s",str);
    17     len=strlen(str);
    18     int i=0,j=1,k=0,pi,pj;
    19     while(1)
    20     {
    21         if(k==len) return i;
    22         if(i==j) j++;//!!
    23         pi=(i+k)%len;
    24         pj=(j+k)%len;
    25         if(str[pi]>str[pj]) i+=k+1,k=0;
    26         else if(str[pj]>str[pi]) j+=k+1,k=0;
    27         else k++;
    28     }
    29 }
    30 
    31 int main()
    32 {
    33     int cas; scanf("%d",&cas);
    34     while(cas--) printf("%d\n",go()+1);
    35     return 0;
    36 }

     其实更容易想到的是后缀自动机。。

    我会告诉你这个是后缀自动机的例题?

    将原串扩充成原来的二倍,构建后缀自动机,然后将原串在后缀自动机上匹配,即可。

    需要在后缀自动机上每个节点搞一个s值表示这个节点所表示的串在扩充后的串中的位置。

    View Code
     1 #include <iostream>
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <algorithm>
     6 
     7 #define N 20010 
     8 
     9 using namespace std;
    10 
    11 struct SAM
    12 {
    13     SAM *son[26],*f;
    14     int l,s;
    15 }sam[N],*head,*last;
    16 
    17 char str[N];
    18 int cnt,len;
    19 
    20 inline void add(int x)
    21 {
    22     SAM *p=&sam[++cnt],*jp=last;
    23     p->l=last->l+1; p->s=p->l;
    24     last=p;
    25     for(;jp&&!jp->son[x];jp=jp->f) jp->son[x]=p;
    26     if(!jp) p->f=head;
    27     else if(jp->l+1==jp->son[x]->l) p->f=jp->son[x];
    28     else
    29     {
    30         SAM *r=&sam[++cnt],*q=jp->son[x];
    31         *r=*q; r->l=jp->l+1;  r->s=p->l;
    32         q->f=p->f=r;
    33         for(;jp&&jp->son[x]==q;jp=jp->f) jp->son[x]=r;
    34     }
    35 }
    36 
    37 inline void read()
    38 {
    39     scanf("%s",str);
    40     len=strlen(str);
    41     memset(&sam,0,sizeof sam);
    42     head=last=&sam[cnt=0];
    43     for(int i=0;i<len;i++) str[i]-='a',str[i+len]=str[i];
    44     for(int i=0;i<(len<<1);i++) add(str[i]);
    45 }
    46 
    47 inline void go()
    48 {
    49     last=head;
    50     for(int i=0;i<len;i++)
    51         for(int j=0;j<26;j++)
    52             if(last->son[j]) {last=last->son[j];break;}
    53     printf("%d\n",last->s-len+1);
    54 }
    55 
    56 int main()
    57 {
    58     int cas; scanf("%d",&cas);
    59     while(cas--) read(),go();
    60     return 0;
    61 } 
  • 相关阅读:
    hmac
    struct模块-黏包的解决方法
    PHPCMS快速建站系列
    Notepad++搜索中的正则应用
    用var 变量=函数名 方式调用函数时如何传值的问题
    ThInkPHP中的常量
    css cursor 的可选值(鼠标的各种样式)
    JS实现用键盘控制DIV上下左右+放大缩小与变色
    PHP定义数组常量
    FormData实现文件上传实例
  • 原文地址:https://www.cnblogs.com/proverbs/p/2919381.html
Copyright © 2011-2022 走看看