poj 3261 Milk Patterns

http://poj.org/problem?id=3261

题意:

求可重复的最长出现k次子串

后缀数组求出height后分组

从大到小每句长度,并查集合并

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>

#define N 20001

using namespace std;

int n,m,tot;
int a[N],has[N];

int v[N];
int p=0,q=1;
int sa[2][N],rk[2][N],height[N];

int fa[N],siz[N];

vector<int>V[N];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

void mul(int k,int *sa,int *rk,int *SA,int *RK)
{
    for(int i=1;i<=n;++i) v[rk[sa[i]]]=i;
    for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
    for(int i=n-k+1;i<=n;++i) SA[v[rk[i]]--]=i;
    for(int i=1;i<=n;++i) RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
}

void presa()
{
    for(int i=1;i<=n;++i) v[a[i]]++;
    for(int i=1;i<=tot;++i) v[i]+=v[i-1];
    for(int i=1;i<=n;++i) sa[p][v[a[i]]--]=i;
    for(int i=1;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    for(int k=1;k<n;k<<=1,swap(p,q)) 
    mul(k,sa[p],rk[p],sa[q],rk[q]);    
}

void get_height()
{
    int j;
    for(int i=1,k=0;i<=n;++i)
    {
        j=sa[p][rk[p][i]-1];
        while(a[i+k]==a[j+k]) k++;
        height[rk[p][i]]=k;
        if(k) k--;
    }
}

int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }

void unionn(int u,int v)
{
    u=find(u);
    v=find(v);
    siz[v]+=siz[u];
    fa[u]=v;
}

void solve()
{
    for(int i=1;i<=n;++i) fa[i]=i,siz[i]=1;
    for(int i=2;i<=n;++i) V[height[i]].push_back(i);
    int w,s;
    for(int i=n;i;--i)
    {
        s=V[i].size();
        if(!s) continue;
        for(int j=0;j<s;++j) 
        {
            w=V[i][j];
            if(find(sa[p][w-1])!=find(sa[p][w])) unionn(sa[p][w-1],sa[p][w]);
            if(w<n && height[w+1]>=i && find(sa[p][w+1])!=find(sa[p][w])) unionn(sa[p][w+1],sa[p][w]);
            if(siz[find(sa[p][w])]>=m) 
            {
                printf("%d",i);
                return;
            }
        }
    }    
}

int main()
{
    read(n); read(m);
    for(int i=1;i<=n;++i) read(a[i]),has[i]=a[i];
    sort(has+1,has+n+1);
    tot=unique(has+1,has+n+1)-has-1;
    for(int i=1;i<=n;++i) a[i]=lower_bound(has+1,has+tot+1,a[i])-has;
    presa();
    get_height();
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8507344.html