hdu5030 Rabbit's String 后缀数组

来源:互联网 发布:软件集成商 编辑:程序博客网 时间:2024/05/17 01:03

把一个字符串最多分为k段,所有每一段的最大子串的最大值最小。

二分答案串是排名多少的字串,根据sum可以定位该串的位置,在t之后的后缀中有些串是需要切割的,这些串加上后一个字符会大于答案串,把这些串的位置求出后贪心最少切多少刀。

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#include<vector>#include<set>#include<map>#include<queue>#include<bitset>#define fi first#define se second#define pii pair<int,int>#define ll long long#define inf 1<<30#define eps 1e-8using namespace std;const int maxn=100005;int n,k;char str[maxn];int s[maxn];ll sum[maxn];int cc[maxn];int t1[maxn],t2[maxn],c[maxn];int sa[maxn],ra[maxn],height[maxn];void buildSa(int s[],int n,int m)//最大值小于m{    int i,j,p,*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++)ra[sa[i]]=i;    for(i=0;i<n;i++)    {        if(k)k--;        j=sa[ra[i]-1];        while(s[i+k]==s[j+k])k++;        height[ra[i]]=k;    }}bool ok(ll mid){    int t=lower_bound(sum,sum+n+1,mid)-sum;    int l=sa[t],r=n-sum[t]+mid-1;    int len=r-l+1;    for(int i=0;i<=n;i++)        cc[i]=-1;    if(l+len-1<n-1)        cc[l]=len;    int ans=0;    for(int i=t+1;i<=n;i++) {        len=min(len,height[i]);        if(len==0) return false;        if(sa[i]+len-1<n-1)            cc[sa[i]]=len;    }    int m=n;    for(int i=0;i<n;i++) {        if(i==m) {            ans++;            if(ans>=k) return false;            m=n;        }        if(cc[i]!=-1) {            m=min(m,i+cc[i]);        }    }    return ans+1<=k;}void solve(){    sum[0]=0;    for(int i=1;i<=n;i++)        sum[i]=sum[i-1]+n-sa[i]-height[i];    ll l=1,r=sum[n];    while(l<r) {        ll mid=(l+r)/2;        if(ok(mid))            r=mid;        else            l=mid+1;    }    int t=lower_bound(sum,sum+n+1,l)-sum;    int le=sa[t];    int rr=n-sum[t]+l-1;    for(int i=le;i<=rr;i++)        putchar(str[i]);    puts("");}int main(){    while(~scanf("%d",&k) && k) {        scanf("%s",str);        n=strlen(str);        for(int i=0;i<=n;i++)            s[i]=str[i];        buildSa(s,n+1,128);        getHeight(s,n);        solve();    }    return 0;}


0 0
原创粉丝点击