#4303. 跳蚤

题意
内存限制:256 MiB
时间限制:1000 ms
很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。

首先,他会把串分成不超过 $k$ 个子串,然后对于每个子串 $S$,他会从 $S$ 的所有子串中选择字典序最大的那一个,并在选出来的 $k$
个子串中选择字典序最大的那一个。他称其为“魔力串”。现在他想找一个最优的分法让“魔力串”字典序最小。

$k \le 15$ , $|S| \le 10^5$
题解
利用 $SAM/SA$ 求出本质不同串个数,进行二分
对于 $mid$ ,利用 $SAM/SA$ 求出其对应的子串 $s$
因为一个串的最大字典序子串一定是其后缀(可以画个图理解一下,所以从后往前枚举,如果 $[i,last]$ 的字典序比 $s$ 大,则必须在 $[i-1,last]$ 分割, $i$ 作为新的一个 $last$
求字典序只需求出最长公共前缀,可以二分 $hash$ 或者 $SA$ 进行处理
我写的是 $SAM$ +二分 $hash$ ,效率 $O(nlogn-nlog^2n)$(我也不会分析了

代码

#include <bits/stdc++.h>
#define K 793999
#define LL long long
#define U unsigned LL
using namespace std;
const int N=2e5+5;
int k,n,lst=1,sz=1,t[N],e[N],tp;
LL s[N],f[N];U b[N],h[N][2];
char str[N],now[N];
struct SAM{
    int link,len,nx[26];
}a[N];
void build(int x){
    int np=++sz,p=lst;
    a[np].len=a[p].len+1;
    while(p && !a[p].nx[x])
        a[p].nx[x]=np,p=a[p].link;
    if (!p) a[np].link=1;
    else{
        int q=a[p].nx[x];
        if (a[q].len==a[p].len+1)
            a[np].link=q;
        else{
            int nq=++sz;
            a[nq]=a[q];
            a[nq].len=a[p].len+1;
            a[q].link=a[np].link=nq;
            while(p && a[p].nx[x]==q)
                a[p].nx[x]=nq,p=a[p].link;
        }
    }
    lst=np;
}
void find(int u,LL v){
    v-=f[u];if (!v) return;
    for (int j,i=0;i<26;i++)
        if ((j=a[u].nx[i])){
            if (v>s[j]) v-=s[j];
            else{
                now[++tp]=i+'a',find(j,v);
                return;
            }
        }
}
U H(int l,int r,bool ty){
    return h[r][ty]-h[l-1][ty]*b[r-l+1];
}
bool cmp(int L,int R){
    int d,l=0,r=min(tp,R-L+1);
    while(l<r){
        d=(l+r+1)>>1;
        if (H(1,d,1)==H(L,L+d-1,0))
            l=d;
        else r=d-1;
    }
    if (l==min(tp,R-L+1))
        return tp>=R-L+1;
    return str[L+l]<now[l+1];
}
bool J(){
    int res=0;
    for (int l=n,r=n;l;){
        while(cmp(l,r) && l) l--;
        if (l==r) return 0;res++;r=l;
        if (res>k) return 0;
    }
    return 1;
}
int main(){
    scanf("%d%s",&k,str+1);
    b[0]=1;n=strlen(str+1);
    for (int i=1;i<=n;i++)
        build(str[i]-'a'),b[i]=b[i-1]*K,
        h[i][0]=h[i-1][0]*K+str[i];
    for (int i=1;i<=sz;i++) e[a[i].len]++,f[i]=1;
    for (int i=1;i<=sz;i++) e[i]+=e[i-1];f[1]=0;
    for (int i=1;i<=sz;i++) t[e[a[i].len]--]=i;
    for (int j,i=sz;i;i--){
        j=t[i];s[j]=f[j];
        for (int l=0;l<26;l++)
            s[j]+=s[a[j].nx[l]];
    }
    LL l=1,r=s[1],d;while(l<r){
        d=(l+r)>>1;tp=0;find(1,d);
        for (int i=1;i<=tp;i++)
            h[i][1]=h[i-1][1]*K+now[i];
        if (J()) r=d;else l=d+1;
    }
    tp=0;find(1,l);
    for (int i=1;i<=tp;i++) putchar(now[i]);putchar('\n');
    return 0; 
}

 

posted @ 2019-04-07 21:22  xjqxjq  阅读(145)  评论(0编辑  收藏  举报