题意:给定一个串,和一个数c,求一个长度最大的公共子串(可以重叠),并且该公共子串出现次数大于c。
题解见罗穗骞论文。
收获:
计算高度函数时,遇到rk[i]==1的点时,要将k设置成0。(k是"h[i-1]-1")。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define maxa 2000001 5 #define maxn 20010 6 using namespace std; 7 8 int n, c; 9 int aa[maxn], vv[maxa], sa[maxn], rk[maxn], ht[maxn]; 10 11 void expand( int k, int sa[maxn], int rk[maxn], int tsa[maxn], int trk[maxn] ) { 12 for( int i=1; i<=n; i++ ) vv[rk[sa[i]]]=i; 13 for( int i=n; i>=1; i-- ) if( sa[i]>k ) tsa[vv[rk[sa[i]-k]]--]=sa[i]-k; 14 for( int i=n-k+1; i<=n; i++ ) tsa[vv[rk[i]]--]=i; 15 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]); 16 } 17 void calcht() { 18 for( int i=1,k=0; i<=n; i++ ) { 19 if( rk[i]==1 ) { 20 ht[i] = k = 0; 21 continue; 22 } 23 int j=sa[rk[i]-1]; 24 while( aa[i+k]==aa[j+k] ) k++; 25 ht[i]=k; 26 if(k>0)k--; 27 } 28 } 29 void suffix() { 30 static int vsa[maxn], vrk[maxn]; 31 for( int i=1; i<=n; i++ ) vv[aa[i]]++; 32 for( int i=1; i<=maxa; i++ ) vv[i]+=vv[i-1]; 33 for( int i=1; i<=n; i++ ) sa[vv[aa[i]]--]=i; 34 for( int i=1; i<=n; i++ ) rk[sa[i]]=rk[sa[i-1]]+(aa[sa[i]]!=aa[sa[i-1]]); 35 int *a=sa, *b=rk, *c=vsa, *d=vrk; 36 for( int k=1; k<n; k<<=1,swap(a,c),swap(b,d) ) expand(k,a,b,c,d); 37 for( int i=1; i<=n; i++ ) sa[i]=a[i],rk[i]=b[i]; 38 calcht(); 39 } 40 bool ok( int len ) { 41 int top=1; 42 for( int i=2; i<=n; i++ ) 43 if( ht[sa[i]]<len ) { 44 if( i-top>=c ) { 45 return true; 46 } 47 top = i; 48 } 49 if( n+1-top>=c ) return true; 50 return false; 51 } 52 int main() { 53 scanf( "%d%d", &n, &c ); 54 for( int i=1; i<=n; i++ ) { 55 scanf( "%d", aa+i ); 56 aa[i]++; 57 } 58 aa[n+1] = -1; 59 suffix(); 60 /* 61 for( int i=1; i<=n; i++ ) { 62 fprintf( stderr, "%d(%d): ", i, ht[sa[i]] ); 63 for( int j=sa[i]; j<=n; j++ ) 64 fprintf( stderr, "%d ", aa[j] ); 65 fprintf( stderr, " " ); 66 } 67 */ 68 int lf=0, rg=n-c+1; 69 while(lf<rg) { 70 int mid=(lf+rg+1)>>1; 71 if( ok(mid) ) lf=mid; 72 else rg=mid-1; 73 } 74 printf( "%d ", lf ); 75 }