题意
给出一个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(" "); 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 ",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 ",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 "); 93 else 94 printf("%d ",ans+1); 95 } 96 return 0; 97 }