【poj1743】Musical Theme 【后缀自动机】

题意

 给出一个n个数字的序列,找出相同变化趋势且不重叠的两个最长子串。

分析

 这个题以前应该用后缀数组+二分做过。学了后缀自动机后可以用后缀自动机搞一下。

  先差分,然后把查分后的数组建SAM。然后对于每个状态记录一个l[u],和r[u],分别代表right集合中,最大的v和最小的v。(这里如果不明白可以去看clj的课件)。

  然后对于每个状态,当这个状态cnt[u]>=2的时候,说明有两个以上的子串,然后min(st[u].len,r[u]-l[u])就是这个状态最长不重叠相同子串的长度。

  

 1 #include <cstring>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstdio>
 5 #include <map>
 6 using namespace std;
 7 const int maxn=20000+100;
 8 const int INF=2147000000;
 9 int s[maxn],a[maxn],n;
10 struct state{
11     int len,link;
12     int next[180];
13 }st[2*maxn];
14 int last,cur,sz;
15 int cnt[2*maxn],l[2*maxn],r[2*maxn],c[2*maxn];
16 void init(){
17     sz=1;
18     last=cur=0;
19     st[0].len=0;
20     st[0].link=-1;
21     memset(st[0].next,0,sizeof(st[0].next));
22 }
23 
24 void build_sam(int c,int pos){
25     cur=sz++;
26     st[cur].len=st[last].len+1;
27     cnt[cur]=1;
28     l[cur]=r[cur]=pos;
29     memset(st[cur].next,0,sizeof(st[cur].next));
30     int p;
31     for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link)
32         st[p].next[c]=cur;
33     if(p==-1)
34         st[cur].link=0;
35     else{
36         int q=st[p].next[c];
37         if(st[q].len==st[p].len+1)
38             st[cur].link=q;
39         else{
40             int clone=sz++;
41             cnt[clone]=r[clone]=0;
42             l[clone]=127;
43             st[clone].len=st[p].len+1;
44             //printf("%d ",st[clone].len);
45             st[clone].link=st[q].link;
46             memcpy(st[clone].next,st[q].next,sizeof(st[clone].next));
47             for(;p!=-1&&st[p].next[c]==q;p=st[p].link){
48                 st[p].next[c]=clone;
49             }
50             st[cur].link=st[q].link=clone;
51         }
52     }
53     last=cur;
54 }
55 int cmp(int a,int b){
56     return st[a].len>st[b].len;
57 }
58 
59 int ans=0;
60 int main(){
61     while(scanf("%d",&n)!=EOF&&n){
62         for(int i=1;i<=n;i++){
63             scanf("%d",&s[i]);
64             a[i]=s[i]-s[i-1];
65         }
66         init();
67         for(int i=1;i<=n;i++){
68             build_sam(a[i]+88,i);
69             //printf("%d ",a[i]);
70         }
71 //        for(int i=0;i<sz;i++)
72 //            printf("%d ",st[i].len);
73 //        printf("\n");
74         for(int i=0;i<sz;i++)
75             c[i]=i;
76         sort(c,c+sz,cmp);
77         ans=0;
78         for(int i=0;i<sz;i++){
79             int o=c[i];
80             if(st[o].link!=-1){
81                 cnt[st[o].link]+=cnt[o];
82                 l[st[o].link]=min(l[st[o].link],l[o]);
83                 r[st[o].link]=max(r[st[o].link],r[o]);
84             }
85          //   printf("%d %d %d %d\n",cnt[o],st[o].len,l[o],r[o]);
86             if(cnt[o]>=2&&min(st[o].len,r[o]-l[o])>=4){
87                 //printf("%d %d\n",l[o],r[o]);
88                 ans=max(ans,min(st[o].len,r[o]-l[o]));
89             }
90         }
91         if(ans<4)
92             printf("0\n");
93         else
94         printf("%d\n",ans+1);
95     }
96 return 0;
97 }
View Code

 

posted @ 2018-11-01 10:21  蒟蒻LQL  阅读(280)  评论(1编辑  收藏  举报