题目大意:
给你一个数列,我们数列中两个串是相似的当且仅当这两个串的长度至少为5、两个串差分后形成的数列一样且不相交,求最长的相似串的长度。
思路:
后缀自动机求最长不相交重复子串。
首先将差分后的数列构造SAM,然后按照拓扑序DP,得到每个状态right集合的最大值t与最小值s,表示当前状态对应的最长的不相交子串为[s,t]。
然而我们还要保证以当前状态结尾的子串的长度能够与[s,t]子串相等,设当前状态对应的最长子串长度为len,则最长相似串的长度为min(t-s+1,len) 。
然后取max即可。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int inf=0x7fffffff; 13 const int LEN=20001; 14 int n; 15 class SuffixAutomaton { 16 private: 17 static const int SIGMA_SIZE=180; 18 struct State { 19 int link,go[SIGMA_SIZE],len,maxright,minright; 20 }; 21 State s[LEN<<1]; 22 int sz,newState(const int l) { 23 sz++; 24 s[sz].len=l; 25 s[sz].minright=inf; 26 return sz; 27 } 28 int root,last; 29 int cnt[LEN],top[LEN<<1]; 30 void tsort() { 31 for(int i=1;i<=sz;i++) cnt[s[i].len]++; 32 for(int i=n;i;i--) cnt[i-1]+=cnt[i]; 33 for(int i=1;i<=sz;i++) top[cnt[s[i].len]--]=i; 34 } 35 public: 36 void reset() { 37 sz=0; 38 memset(s,0,sizeof s); 39 root=last=newState(0); 40 memset(cnt,0,sizeof cnt); 41 } 42 void extend(const int w) { 43 int p=last,new_p=newState(s[last].len+1); 44 s[new_p].maxright=s[new_p].minright=s[new_p].len; 45 while(p&&!s[p].go[w]) { 46 s[p].go[w]=new_p; 47 p=s[p].link; 48 } 49 if(!p) { 50 s[new_p].link=root; 51 } else { 52 int q=s[p].go[w]; 53 if(s[q].len==s[p].len+1) { 54 s[new_p].link=q; 55 } else { 56 int new_q=newState(s[p].len+1); 57 memcpy(s[new_q].go,s[q].go,sizeof s[q].go); 58 s[new_q].link=s[q].link; 59 s[q].link=s[new_p].link=new_q; 60 while(p&&s[p].go[w]==q) { 61 s[p].go[w]=new_q; 62 p=s[p].link; 63 } 64 } 65 } 66 last=new_p; 67 } 68 int stat() { 69 tsort(); 70 for(int i=1;i<=sz;i++) { 71 int p=top[i],q=s[top[i]].link; 72 s[q].maxright=std::max(s[q].maxright,s[p].maxright); 73 s[q].minright=std::min(s[q].minright,s[p].minright); 74 } 75 int ret=0; 76 for(int i=1;i<=sz;i++) { 77 ret=std::max(ret,std::min(s[i].maxright-s[i].minright+1,s[i].len+1)); 78 } 79 return ret>=5?ret:0; 80 } 81 }; 82 SuffixAutomaton sam; 83 int s[LEN]; 84 int main() { 85 for(;;) { 86 n=getint(); 87 if(!n) return 0; 88 sam.reset(); 89 for(int i=1;i<=n;i++) s[i]=getint(); 90 for(int i=1;i<n;i++) sam.extend(s[i]=s[i+1]-s[i]+88); 91 printf("%d ",sam.stat()); 92 } 93 }