真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[BZOJ 4310]跳蚤

[BZOJ 4310]跳蚤

题目

很久很久以前,森林里住着一群跳蚤。一天,跳蚤国王得到了一个神秘的字符串,它想进行研究。
首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个,并在选出来的 k 个子串中选择字典序最大的那一个。他称其为“魔力串”。
现在他想找一个最优的分法让“魔力串”字典序最小。

INPUT

第一行一个整数 k。
接下来一个长度不超过 105 的字符串 S。

OUTPUT

输出一行,表示字典序最小的“魔力串”。

SAMPLE

INPUT

13
bcbcbacbbbbbabbacbcbacbbababaabbbaabacacbbbccaccbcaabcacbacbcabaacbccbbcbcbacccbcccbbcaacabacaaaaaba

OUTPUT

cbc

解题报告

BZOJ上榜留念2333(我TM打了一个下午)

首先我们看到题目要求的是最大值最小,那么我们考虑二分

我们很容易知道,所有本质不同的字串数为$\sum_{i}^{len}len-sa[i]-height[i]$

(这个很容易由SA与height的含义推得,这里就不再展开证明了)

那么我们二分第$mid$个字串,去判断这个字串是否满足条件

判断就很好判断了(虽然我TM就是在这调了一下午),我们利用贪心的思想,从后向前枚举,然后判断是否要分开,最后判断分开次数与$k$的关系即可

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 using namespace std;
  6 char s[100005];
  7 int n,m;
  8 int t1[100005],t2[100005],t3[100005],buc[100005];
  9 int sa[100005],rank[100005],height[100005];
 10 inline void Suffix(){
 11     int i,j,k(0),p(0),*x(t1),*y(t2),*t;
 12     for(i=0;i<=m;++i)buc[i]=0;
 13     for(i=1;i<=n;++i)++buc[x[i]=s[i]];
 14     for(i=1;i<=m;++i)buc[i]+=buc[i-1];
 15     for(i=n;i>=1;--i)sa[buc[x[i]]--]=i;
 16     for(j=1;p<n;j<<=1,m=p){
 17         for(p=0,i=n-j+1;i<=n;++i)y[++p]=i;
 18         for(i=1;i<=n;++i)
 19             if(sa[i]>j)
 20                 y[++p]=sa[i]-j;
 21         for(i=0;i<=m;++i)buc[i]=0;
 22         for(i=1;i<=n;++i)t3[i]=x[y[i]];
 23         for(i=1;i<=n;++i)++buc[t3[i]];
 24         for(i=1;i<=m;++i)buc[i]+=buc[i-1];
 25         for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i];
 26         for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;++i)
 27             x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p;
 28     }
 29     for(i=1;i<=n;++i)rank[sa[i]]=i;
 30     for(i=1;i<=n;height[rank[i++]]=k)
 31         for(k?--k:0,j=sa[rank[i]-1];s[i+k]==s[j+k];++k);
 32 }
 33 int k;
 34 typedef long long L;
 35 L tot;
 36 int ansl,ansr,ll,rr;
 37 /*inline void get_kth(L x){
 38     for(int i=1;i<=n;++i){
 39         if(x>(L)(n-sa[i]-height[i]+1))
 40             x-=(L)(n-sa[i]-height[i]+1);
 41         else{
 42             ll=sa[i],rr=sa[i]+height[i]+k-1;
 43             return;
 44         }
 45     }
 46 }*/
 47 inline bool cmp(int l,int r){
 48     for(int i=l,j=ll;i<=r&&j<=rr;++i,++j){
 49         if(s[i]<s[j])
 50             return true;
 51         if(s[i]>s[j])
 52             return false;
 53     }
 54 //  cout<<l<<' '<<r<<' '<<ll<<' '<<rr<<endl;
 55     if(rr-ll<r-l)
 56         return false;
 57     return true;
 58 }
 59 inline bool check(){
 60     int i,j,cnt(0);
 61     for(i=n;i>=1;i=j,++cnt){
 62         for(j=i;j>0;--j)
 63             if(!cmp(j,i))
 64                 break;
 65         if(i==j)
 66             return false;
 67     }
 68     return cnt<=k;
 69 }
 70 L sum[100005];
 71 int main(){
 72     scanf("%d%s",&k,s+1);
 73     n=strlen(s+1);
 74     m=130;
 75     Suffix();
 76     tot=n;
 77     for(int i=1;i<=n;++i){
 78         sum[i]=n-sa[i]+1-height[i];
 79         sum[i]+=sum[i-1];
 80         tot+=n-sa[i]-height[i];
 81     }
 82     L l(0),r(tot);
 83     while(l<=r){
 84         L mid((l+r)>>1);
 85 //      cout<<l<<' '<<r<<" "<<mid<<endl;
 86 //      get_kth(mid);
 87         L tmp(lower_bound(sum+1,sum+n+1,mid)-sum);
 88         ll=sa[tmp],rr=mid-sum[tmp-1]+sa[tmp]+height[tmp]-1;
 89 //      cout<<ll<<' '<<rr<<' '<<mid<<endl;
 90         if(check()){
 91             ansl=ll,ansr=rr;
 92             r=mid-1;
 93         }
 94         else
 95             l=mid+1;
 96     }
 97 //  cout<<ansl<<' '<<ansr<<endl;
 98     for(int i=ansl;i<=ansr;++i)
 99         putchar(s[i]);
100 }
View Code

 

posted @ 2017-09-22 17:48  Hzoi_Mafia  阅读(300)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神