bzoj4486: [Jsoi2015]串分割

肉丝哥哥钦定好题 话说我的blog现在为什么到处都是肉丝哥哥

先来想一个弱化版,假如能够n整除K怎么做?

把每个数字看成一个字符串,按字典序排名,这个可以后缀数组解决,然后暴力枚举每种情况,O(1)判两个长度为n/K的数字大小即可

然后不能整除一定是有n-n/K*K个长度为n/K+1的数字

先二分答案排名,枚举起始位置,考虑一个贪心的做法,假如当前能够放一个长度为n/K+1的就立刻放,这样能够保证最优

why?放n/K+1和n/K的区别相当于多往前走了1步,但是多用了一组n/K+1,假如走n/K在未来某一决策能够走n/K+1,那么当前走n/K+1只需付出少用一组就可以拉回同一起跑线。其实也就是具有决策包容性

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int _=1e2;
const int maxn=2*2e5+_;
int n,K,U;char ss[maxn];

int sa[maxn],Rank[maxn];
namespace SA
{
    int Rsort[maxn],tt[maxn];
    void getsa(int n,int m)
    {
        for(int i=1;i<=n;i++)Rank[i]=ss[i]-'0';
        
        memset(Rsort,0,sizeof(Rsort));
        for(int i=1;i<=n;i++)Rsort[Rank[i]]++;
        for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
        for(int i=n;i>=1;i--)sa[Rsort[Rank[i]]--]=i;
        
        int ln=1,p=0;
        while(p<n)
        {
            int k=0;for(int i=n-ln+1;i<=n;i++)tt[++k]=i;
            for(int i=1;i<=n;i++)
                if(sa[i]-ln>0)tt[++k]=sa[i]-ln;
                
            memset(Rsort,0,sizeof(Rsort));
            for(int i=1;i<=n;i++)Rsort[Rank[tt[i]]]++;
            for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1];
            for(int i=n;i>=1;i--)sa[Rsort[Rank[tt[i]]]--]=tt[i];
            
            for(int i=1;i<=n;i++)tt[i]=Rank[i];
            
            p=1;Rank[sa[1]]=1;
            for(int i=2;i<=n;i++)
            {
                if(tt[sa[i]]!=tt[sa[i-1]]||tt[sa[i]+ln]!=tt[sa[i-1]+ln])p++;
                Rank[sa[i]]=p;
            }
            
            m=p;ln*=2;
        }
    }
    void GetTrueRank(int n)
    {
        int p=0;
        for(int i=1;i<=2*n-1;i++)
            if(sa[i]<=n)Rank[sa[i]]=Rank[sa[i]+n]=++p;
        
        for(int i=1;i<=n;i++)sa[Rank[i]]=i;
    }    
    void main(int n){getsa(2*n-1,15);GetTrueRank(n);}
}

namespace PRINT
{
    void main(int ans,int len)
    {
        int st=sa[ans];
        for(int i=1;i<=len;i++)putchar(ss[i+st-1]);
        puts("");
    }
}
namespace SOL1
{
    void main()
    {
        int ans=(1<<30);
        for(int i=1;i<=U;i++)
        {
            int num=0,tt=0;
            for(int j=1;j<=K;j++)
                num=max(num,Rank[i+tt]),tt+=U;
            ans=min(ans,num);
        }
        PRINT::main(ans,U);
    }
}
namespace SOL2
{
    int calc(int em)
    {
        int mmax=0;
        for(int i=1;i<=U+1;i++)
        {
            int p=i,num=0;
            for(int j=1;j<=K;j++)
            {
                if(Rank[p]<=em)p+=U+1,num++;
                else p+=U;
                if(p>=i+n-1)break;
            }
            mmax=max(mmax,num);
        }
        return mmax;
    }
    void main()
    {
        int res=n-U*K;
        int el=1,er=n,em,ans;
        while(el<=er)
        {
            em=(el+er)/2;
            if(calc(em)>=res)
            {
                er=em-1;
                ans=em;
            }
            else el=em+1;
        }
        PRINT::main(ans,U+1);
    }
}

int main()
{
    scanf("%d%d%s",&n,&K,ss+1); U=n/K;
    for(int i=1;i<n;i++)ss[i+n]=ss[i];
    SA::main(n);
    
    if(n%K==0)SOL1::main();
    else SOL2::main();
    
    return 0;
}

 

posted @ 2019-03-29 16:26  AKCqhzdy  阅读(238)  评论(0编辑  收藏  举报