思路:要求A中两子串之差为定值,将每相邻两个数相减所得数列B,等价于要求B中子串相等。从而转换LCP(longest commen prefix)问题,又要求不能重叠,采用二分答案方法求解。要注意的是二分期间的判断search_ans:若果h[i]>=len,并且h[j]>=len,则sa[i]..s[j]中的最大与最小值之差即为重叠瓶颈!
- #include <iostream>
- #include <string>
- #include <algorithm>
- using namespace std;
- #define Min(a,b) (a)<(b)?(a):(b)
- #define Max(a,b) (a)>(b)?(a):(b)
- const int N = 41000;
- const int D = 10;
- const int M = 200, offset = 100;
- int n;
- int s[N];
- int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, h[N];
- // lcp[i][j]: longest commen prefix ( suffix(sa[k+1]), suffix(sa[k]) ) j <= k < j+2^i
- void radix_sort()
- {
- int i, j, k;
- rank = mem[0];
- nrank = mem[1];
- sa = mem[2];
- nsa = mem[3];
- for(i = 0; i < n; i++) cnt[s[i]]++;
- for(i = 1; i < M; i++) cnt[i] += cnt[i-1];
- for(i = n-1; i >= 0; i--) sa[--cnt[s[i]]] = i;
- for(rank[0]=0, i=1; i < n; i++)
- {
- rank[sa[i]] = rank[sa[i-1]];
- if(s[sa[i]]!=s[sa[i-1]]) rank[sa[i]]++;
- }
- for(k = 1; k<n && rank[sa[n-1]] < n-1; k*=2)
- {
- for(i = 0; i < n; i++) cnt[rank[sa[i]]] = i+1;
- for(i = n-1; i >= 0; i--) if(sa[i]-k>=0)
- nsa[--cnt[rank[sa[i]-k]]] = sa[i]-k;
- // max(sa[i]-k)=n-k-1 , therefore i = n-k;
- for(i = n-k; i < n; i++)
- nsa[--cnt[rank[i]]] = i;
- for(nrank[nsa[0]], i=1; i < n; i++)
- {
- nrank[nsa[i]] = nrank[nsa[i-1]];
- if(rank[nsa[i]] != rank[nsa[i-1]]
- || rank[nsa[i]+k] != rank[nsa[i-1]+k])
- nrank[nsa[i]]++;
- }
- swap(rank, nrank);
- swap(sa, nsa);
- }
- }
- void get_lcp_rmq()
- {
- int i, j, k;
- for(i=0,k=0; i<n; i++)
- {
- if(rank[i]==n-1) h[rank[i]]=k=0;
- else
- {
- if(k>0)k--;
- j = sa[rank[i]+1];
- for(;s[i+k]==s[j+k];k++) ;
- h[rank[i]]=k;
- }
- }
- }
- /*
- 9
- 1 2 3 4 5 6 7 8 9
- */
- bool search_ans(int len)
- {
- int i, l=N, r=0, ma, mi;
- for(i = 0; i < n-2; i++)
- {
- if( h[i] < len) l=N,r=0;
- else
- {
- mi = sa[i];
- ma = sa[i+1];
- if(mi > ma) swap(mi,ma);
- l = Min(mi, l);
- r = Max(ma, r);
- if(r - l >= len)return true;
- }
- }
- return false;
- }
- int main()
- {
- int i, j, k;
- while(scanf("%d", &n)==1 && n)
- {
- memset(cnt, 0, sizeof(cnt));
- memset(mem, 0, sizeof(mem));
- for(i=0;i<n;i++) scanf("%d",&s[i]);
- for(i=0;i<n-1;i++) s[i] = s[i+1]-s[i]+offset;
- s[n-1]=0;
- //for(i=0;i<n;i++)printf("%d ",s[i]); puts("");
- radix_sort();
- get_lcp_rmq();
- int low = 0, up = n, mid;
- bool get=0;
- while(low < up)
- {
- mid = (low+up+1)/2;
- if( get=search_ans(mid) ) low = mid;
- else up = mid-1;
- }
- if(low < 4)puts("0");
- else printf("%d/n", low+1);
- }
- return 0;
- }