poj 1743
题意:给出一个串,求两个不相交的长度相等的子串,使得对应位置的差相等。
题解:首先,假设串是a[0],a[1],...a[n],先作差,即a[1]=a[1]-a[0],a[2]=a[2]-a[1],a[i]=a[i]-a[i-1],然后我们求a[1],a[2],a[3],...a[n]的两个不相交的公共子串。
先将h数组求出来,然后二分子串长度,。。。。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define maxn 20010 5 using namespace std; 6 7 int n; 8 int aa[maxn], sa[maxn], rk[maxn], ht[maxn], vv[maxn]; 9 10 void expand( int k, int sa[maxn], int rk[maxn], int tsa[maxn], int trk[maxn] ) { 11 for( int i=1; i<=n; i++ ) vv[rk[sa[i]]]=i; 12 for( int i=n; i>=1; i-- ) if( sa[i]>k ) tsa[vv[rk[sa[i]-k]]--]=sa[i]-k; 13 for( int i=n-k+1; i<=n; i++ ) tsa[vv[rk[i]]--]=i; 14 for( int i=1; i<=n; i++ ) trk[tsa[i]]=trk[tsa[i-1]]+(rk[tsa[i]]!=rk[tsa[i-1]]||rk[tsa[i]+k]!=rk[tsa[i-1]+k]); 15 } 16 void calcht() { 17 int k=0; 18 ht[sa[1]]=0; 19 for( int i=1; i<=n; i++ ) { 20 if( rk[i]==1 ) continue; 21 int j=sa[rk[i]-1]; 22 while( aa[i+k]==aa[j+k] ) k++; 23 ht[i] = k; 24 if( k>0 ) k--; 25 } 26 } 27 void suffix() { 28 static int tsa[maxn], trk[maxn]; 29 for( int i=1; i<=180; i++ ) vv[i]=0; 30 for( int i=1; i<=n; i++ ) vv[aa[i]]++; 31 for( int i=1; i<=180; i++ ) vv[i]+=vv[i-1]; 32 for( int i=1; i<=n; i++ ) sa[vv[aa[i]]--]=i; 33 for( int i=1; i<=n; i++ ) rk[sa[i]]=rk[sa[i-1]]+(aa[sa[i]]!=aa[sa[i-1]]); 34 int *pa=sa, *pb=rk, *pc=tsa, *pd=trk; 35 for( int k=1; k<n; k<<=1,swap(pa,pc),swap(pb,pd) ) 36 expand(k,pa,pb,pc,pd); 37 if( pa!=sa ) memcpy( sa, tsa, sizeof(sa) ), memcpy( rk, trk, sizeof(rk) ); 38 calcht(); 39 } 40 bool ok( int len ) { // len>=1 41 int top, minp, maxp; 42 top = minp = maxp = sa[1]; 43 for( int i=2; i<=n; i++ ) { 44 if( ht[sa[i]]<len ) { 45 if( maxp-minp>=len ) return true; 46 top = minp = maxp = sa[i]; 47 } else { 48 if( minp>sa[i] ) minp=sa[i]; 49 if( maxp<sa[i] ) maxp=sa[i]; 50 } 51 } 52 if( maxp-minp>=len ) return true; 53 return false; 54 } 55 int main() { 56 while( scanf("%d",&n)==1 ) { 57 if( n==0 ) break; 58 n--; 59 for( int i=0; i<=n; i++ ) 60 scanf( "%d", aa+i ); 61 for( int i=n; i>=1; i-- ) 62 aa[i]=aa[i]-aa[i-1]+88; 63 suffix(); 64 int lf=0, rg=n/2; 65 while( lf<rg ) { 66 int mid=(lf+rg+1)>>1; 67 if( ok(mid) ) lf=mid; 68 else rg=mid-1; 69 } 70 lf++; 71 printf( "%d\n", lf<5 ? 0 : lf ); 72 } 73 }