题目要求最长不重叠的长度相同的子串长度,使得对应的差为定值。
先用后缀数组求出h数组(h[i] = LCP(i-1,i) (LCP是最长公共前缀)),但由于这题目要求子串间不能重叠,因此采用二分答案的方法,根据排序好的相邻后缀的关系,比较它们之间的距离差是否大于答案即可。
下面程序中RMQ部分没有调用,本题不需此内容。
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #define max(a,b) (a>b?a:b)
- const int N = 20100;
- const int INF = 1<<30;
- int n;
- int s[N];
- int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, h[N];
- int d[N][30];
- void radix_sort()
- {
- int i, k;
- rank = mem[0];
- nrank = mem[1];
- sa = mem[2];
- nsa = mem[3];
- memset( cnt, 0, sizeof(cnt));
- memset( mem, 0, sizeof(mem));
- for(i = 0; i < n; i++) cnt[s[i]]++;
- for(i = 1; i < 200; 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;
- }
- for(i = n-k; i < n; i++)
- nsa[--cnt[rank[i]]] = i;
- /*//
- for ( i=0; i<n; i++ )
- printf("%d ", nsa[i] );
- printf("/n" );
- /*/
- for(nrank[nsa[0]]=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]]++;
- }
- int *stemp = rank; rank = nrank; nrank = stemp;
- stemp = sa; sa = nsa; nsa = stemp;
- }
- }
- void initRMQ( int *D, int top)
- {
- int i , j ,k,sk;
- for( i = 0 ; i < top ; i ++ )
- d[i][0] = i;
- for( j = 1 ,k=2; k <= top ; j ++,k <<= 1 )
- {
- for( i = 0 ; i < top ; i ++ )
- {
- sk = i+(k>>1) ;
- d[i][j] = d[i][j-1] ;
- if( sk < top && D[d[i][j]] >= D[d[sk][j-1]] )
- d[i][j] = d[sk][j-1] ;
- }
- }
- }
- int RMQ( int *D , int i , int j )
- {
- //int k = log22[j-i+1] ;
- int k = int(log(j-i+1.0)/log(2.0)) ;
- int k2 = (1 << k)-1;
- if( D[d[i][k]] < D[d[j-k2][k]] )
- return d[i][k];
- else
- return d[j-k2][k];
- }
- void get_lcp_rmq()
- {
- int i, j, k;
- memset( h, 0, sizeof(h));
- for (j = 0, i = 0; i < n; i++)
- {
- if (rank[i] == 0)
- h[0] = j = 0;
- else
- {
- k = sa[rank[i]-1];
- for (j = max(j-1,0); s[i+j] == s[k+j]; j++);
- h[rank[i]] = j;
- }
- }
- // initRMQ( h, n );
- }
- int check( int x )
- {
- int i;
- int min = n, max = 0;
- int tmp;
- for ( i=1; i<n; i++ )
- {
- if ( h[i]<x )
- {
- min = n;
- max = 0;
- }
- else
- {
- int ta = sa[i-1];
- int tb = sa[i];
- if ( ta>tb )
- {
- tmp = ta;
- ta = tb;
- tb = tmp;
- }
- if ( ta<min )
- min = ta;
- if ( tb>max )
- max = tb;
- if ( max-min>x )
- return 1;
- }
- }
- return 0;
- }
- int main ()
- {
- int i;
- while ( scanf("%d", &n)!=EOF && n!=0 )
- {
- int pre, now;
- scanf("%d", &pre );
- for ( i=0; i<n-1; i++ )
- {
- scanf("%d", &now );
- s[i] = now-pre+100;
- pre = now;
- }
- s[n-1] = -INF;
- radix_sort();
- get_lcp_rmq();
- int l = 0, r = n/2+1;
- while ( l<r-1 )
- {
- int mid = (l+r)/2;
- if ( check(mid) )
- l = mid;
- else
- r = mid;
- }
- if ( check(r) && r>=4 )
- printf("%d/n", r+1 );
- else if ( check(l) && l>=4 )
- printf("%d/n", l+1 );
- else
- printf("0/n");
- }
- return 0;
- }