bzoj4310

题解:

后缀数组求出本质不同的串

然后二分答案

贪心判断是否可行

代码:

#include<bits/stdc++.h>
const int N=100010;
using namespace std;
typedef long long ll;
char s[N];
ll L,R,mid;
int K,n,rk[N],sa[N],height[N],tmp[N],cnt[N],Log[N];
int f[16][N],g[N],len,nowl,nowr,ansl,ansr;
void SA(int n,int m)
{
      n++;
      for (int i=0;i<n;i++)cnt[rk[i]=s[i]]++;
      for (int i=1;i<m;i++)cnt[i]+=cnt[i-1];
      for (int i=0;i<n;i++)sa[--cnt[rk[i]]]=i;
      for (int k=1;k<=n;k<<=1)
       {
        for (int i=0;i<n;i++)
         {
              int j=sa[i]-k;
              if (j<0)j+=n;
              tmp[cnt[rk[j]]++]=j;
           }
          int j=0; 
        sa[tmp[cnt[0]=0]]=j=0;
        for (int i=1;i<n;i++)
         {
              if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i;
             sa[tmp[i]]=j;
         }
        memcpy(rk,sa,n*sizeof(int));
        memcpy(sa,tmp,n*sizeof(int));
        if (j>=n-1)break;
       }
      for (int i,k,j=rk[height[i=k=0]=0];i<n-1;i++,k++)
     while (~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1];
}
int lcp(int x,int y)
{
      if (x==y)return n-x;
      x=rk[x],y=rk[y];
      if (x>y)swap(x,y);
      int k=Log[y-x];
      return min(f[k][x+1],f[k][y-(1<<k)+1]);
}
void kth(ll k)
{
      ll s=0;
      for (int i=1;i<=n;s+=n-sa[i]-height[i],i++)
     if (s+n-sa[i]-height[i]>=k)
      {
        nowl=sa[i],nowr=nowl+height[i]+k-s-1;
        len=nowr-nowl+1;
        return;
        }
}
int ask(int l,int r)
{
      int t=min(lcp(l,nowl),min(r-l+1,len));
      if (t==r-l+1&&t<=len)return 1;
      if (t==len)return 0;
      return s[l+t]<=s[nowl+t];
}
int check()
{
    int j,k=0;
      for (int i=n-1;~i;i=j,k++)
     {
        for (j=i;~j;j--)
         if (!ask(j,i))break;
        if (j==i)return 0;
        }
  return k<=K;
}
int main()
{
      scanf("%d%s",&K,s);
      n=strlen(s);
     SA(n,128);
      for (int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
      for (int i=1;i<=n;i++)f[0][i]=height[i];
      for (int j=1;j<17;j++)
     for (int i=1;i+(1<<j-1)<=n;i++)f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
      for (int i=1;i<=n;i++)R+=n-sa[i]-height[i];
     while (L<=R)
     {
        kth(mid=(L+R)>>1);
        if (check())ansl=nowl,ansr=nowr,R=mid-1;
        else L=mid+1;
       }
      for (int i=ansl;i<=ansr;i++)putchar(s[i]);
      return 0;
}
原文地址:https://www.cnblogs.com/xuanyiming/p/8503697.html