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 } 

 

 

posted @ 2013-02-20 20:30  proverbs  阅读(1059)  评论(0编辑  收藏  举报