bzoj 3261

题意:给定一个串,和一个数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 }
View Code
原文地址:https://www.cnblogs.com/idy002/p/4345520.html