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 } 

 

 

你可能感兴趣的:(poj)