• 跳蚤


     跳蚤

    很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。

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

    第一行一个整数 $k le 15$
    接下来一个长度不超过 $10^5$ 的字符串 


    Sol

    建sam,求出总共有多少子串。

    可以二分答案k,然后求出第k大的串。

    贪心从后往前取,遇到不合法就开新的一段,最后判断段数是否<=k

    这样一定是对的。遇到不合法的串再怎么加字符也不合法。

    遇到这种答案有单调性的可以选择二分。

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 2000005
    #define ll unsigned long long
    #define mod 1000000007
    using namespace std;
    int n,num,rt=1,la=1,cnt=1;
    int ord[maxn],sz[maxn],top;
    ll sum[maxn],hash[maxn],ha[maxn],p[maxn];
    char ch[maxn],a[maxn];
    struct node{
        int nex[26],par,Max;
    }s[maxn*2];
    void ins(int c){
        int np=++cnt,p=la;la=np;
        s[np].Max=s[p].Max+1;
        for(;p&&!s[p].nex[c];p=s[p].par)s[p].nex[c]=np;
        if(!p)s[np].par=rt;
        else {
            int q=s[p].nex[c];
            if(s[q].Max==s[p].Max+1)s[np].par=q;
            else {
                int nq=++cnt;
                s[nq].par=s[q].par;s[nq].Max=s[p].Max+1;
                for(int i=0;i<26;i++)s[nq].nex[i]=s[q].nex[i];
                s[q].par=s[np].par=nq;
                for(;p&&s[p].nex[c]==q;p=s[p].par)s[p].nex[c]=nq;
            }
        }
    }
    void calc(){
        int tax[maxn];
        for(int i=1;i<=cnt;i++)tax[s[i].Max]++;
        for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1];
        for(int i=1;i<=cnt;i++)ord[tax[s[i].Max]--]=i;
        for(int i=2;i<=cnt;i++)sz[i]=1;sz[1]=0;
        for(int i=cnt;i>=1;i--){
            int k=ord[i];
            for(int j=0;j<26;j++)sum[k]+=sum[s[k].nex[j]];
            sum[k]+=sz[k];
        }
    }
    void get(ll x){
        top=0;
        int k=rt;
        while(1){
            if(x<=sz[k])break;
            for(int i=0;i<26;i++){
                if(sum[s[k].nex[i]]+sz[k]>=x){
                    a[++top]=i+'a';x-=sz[k];
                    k=s[k].nex[i];break;
                }
                else x-=sum[s[k].nex[i]];
            }
        }
        for(int i=1;i<=top;i++)ha[i]=ha[i-1]*mod+a[i];
    }
    bool check(int li,int ri){
        int len=ri-li+1;
        int l=0,r=min(len,top);
        while(l<r){
            int mid=l+r+1>>1;
            if(hash[li+mid-1]-hash[li-1]*p[mid]==ha[mid])l=mid;
            else r=mid-1;
        }
        if(l==top&&l==len)return 1;
        if(l==top)return 0;
        if(l==len)return 1; 
        return a[l+1]>ch[li+l];
        //a>li~ri  1  else 0
    }
    bool pd(){
        int la=n,co=0;
        for(int i=n;i>=1;i--){
            if(!check(i,la)){
                if(la==i)return 0;
                la=i,co++;i++;
            } 
            if(co>num)return 0;
        }
        if(co+1>num)return 0;
        return 1;
    }
    int main(){
        scanf("%d",&num);
        scanf("%s",ch+1);n=strlen(ch+1);p[0]=1;
        for(int i=1;i<=n;i++){
            ins(ch[i]-'a');
            hash[i]=hash[i-1]*mod+ch[i];
            p[i]=p[i-1]*mod;
        }
        calc();
        ll l=1,r=sum[1];
        while(l<r){
            ll mid=l+r>>1;
            get(mid);
            if(pd())r=mid;
            else l=mid+1; 
        }
        get(l);
        for(int i=1;i<=top;i++)printf("%c",a[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    关于云计算:IaaS的四个误解和四个猜想 浪峰小园子
    国外10个优秀的免费轻量级CMS系统 浪峰小园子
    Win8下80端口被System占用,造成Apache不能启动的解决办法 浪峰小园子
    [转载]基于内存数据库的分布式数据库架构何坤 浪峰小园子
    php短域名转换为实际域名函数 浪峰小园子
    [转载]苹果公司与分工原理 浪峰小园子
    PHPer的等级划分
    简单的无限分类树
    转换字符串编码
    php开启虚拟域名功能
  • 原文地址:https://www.cnblogs.com/liankewei/p/10667206.html
Copyright © 2020-2023  润新知