POJ3261 Milk Patterns

可重叠的k次最长重复子串
利用后缀数组计算S和height数组
然后二分,进行分组~

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+14;
int sa[maxn];
int t1[maxn];
int t2[maxn];
int c[maxn];
int rk[maxn];
int height[maxn];
void build_sa (int s[],int n,int m) {
    int i,j,p;
    int *x=t1,*y=t2;
    for (i=0;i<m;i++) c[i]=0;
    for (i=0;i<n;i++) c[x[i]=s[i]]++;
    for (i=1;i<m;i++) c[i]+=c[i-1];
    for (i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for (j=1;j<=n;j<<=1) {
        p=0;
        for (i=n-j;i<n;i++) y[p++]=i;
        for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
        for (i=0;i<m;i++) c[i]=0;
        for (i=0;i<n;i++) c[x[y[i]]]++;
        for (i=1;i<m;i++) c[i]+=c[i-1];
        for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;
        x[sa[0]]=0;
        for (i=1;i<n;i++) 
        x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
        if (p>=n) break;
        m=p; 
    }
}
void getHeight (int s[],int n) {
    int i,j,k=0;
    for (i=0;i<=n;i++) rk[sa[i]]=i;
    for (i=0;i<n;i++) {
        if (k) k--;
        j=sa[rk[i]-1];
        while (s[i+k]==s[j+k]) k++;
        height[rk[i]]=k;
    }
}
bool check (int n,int k,int t) {
    int num=1;
    for (int i=2;i<=n;i++) {
        if (height[i]>=t) {
            num++;
            if (num>=k) return true;
        }
        else num=1;
    }
    return false;
}
int s[maxn];
int main () {
    int n,k;
    while (scanf("%d%d",&n,&k)==2) {
        int Max=0;
        for (int i=0;i<n;i++) {
            scanf ("%d",&s[i]);
            Max=max(Max,s[i]);
        }
        s[n]=0;
        build_sa(s,n+1,Max+1);
        getHeight(s,n);
        int l=0,r=n;
        int ans=0;
        while (l<=r) {
            int mid=(l+r)>>1;
            if (check(n,k,mid)) {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        printf ("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zhanglichen/p/12332637.html