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
", lf<5 ? 0 : lf  );
72     }
73 }
View Code
原文地址:https://www.cnblogs.com/idy002/p/4345371.html