zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    〖Linux〗Kubuntu设置打开应用时就只在打开时的工作区显示
    〖Linux〗Kubuntu, the application 'Google Chrome' has requested to open the wallet 'kdewallet'解决方法
    unity, dll is not allowed to be included or could not be found
    android check box 自定义图片
    unity, ios skin crash
    unity, Collider2D.bounds的一个坑
    unity, ContentSizeFitter立即生效
    类里的通用成员函数应声明为static
    unity, Gizmos.DrawMesh一个坑
    直线切割凹多边形
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/8503697.html
Copyright © 2011-2022 走看看