题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310

二分答案——在本质不同的子串中二分答案!

如果二分到的子串位置是 st,考虑何时必须分出一段;

如果一个位置 i 有 rk[i] < rk[st],那么显然不用管( i 后缀的开头);

而如果 rk[i] > rk[st],则 i+1 ~ i+LCP 之间必须有一处断开;

比较麻烦的是这样只保证了 i 这个后缀的开头不会产生大于二分子串的子串,但后面怎么办?

这时就又需要考虑到——后缀的后缀也是后缀!所以倒着做,就不用考虑开头后面的问题了!

然后如果必须断开,断开处贪心地靠前即可。

代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. int const xn=1e5+;
  8. int n,m,K,rk[xn],sa[xn],tp[xn],tax[xn],ht[xn][],bin[],bit[xn],dc[xn];
  9. ll sum[xn];
  10. char s[xn],ch[xn];
  11. void Rsort()
  12. {
  13. for(int i=;i<=m;i++)tax[i]=;
  14. for(int i=;i<=n;i++)tax[rk[tp[i]]]++;
  15. for(int i=;i<=m;i++)tax[i]+=tax[i-];
  16. for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
  17. }
  18. void work()
  19. {
  20. for(int i=;i<=n;i++)rk[i]=s[i],tp[i]=i;
  21. Rsort();
  22. for(int k=;k<=n;k<<=)
  23. {
  24. int num=;
  25. for(int i=n-k+;i<=n;i++)tp[++num]=i;
  26. for(int i=;i<=n;i++)
  27. if(sa[i]>k)tp[++num]=sa[i]-k;
  28. Rsort(); swap(rk,tp);
  29. rk[sa[]]=; num=;
  30. for(int i=;i<=n;i++)
  31. rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[sa[i]+k]==tp[sa[i-]+k])?num:++num;
  32. if(num==n)break;
  33. m=num;
  34. }
  35. }
  36. void get()
  37. {
  38. int k=;
  39. for(int i=;i<=n;i++)
  40. {
  41. if(rk[i]==)continue;
  42. if(k)k--; int j=sa[rk[i]-];
  43. while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
  44. ht[rk[i]][]=k;
  45. }
  46. bin[]=; for(int i=;i<;i++)bin[i]=(bin[i-]<<);
  47. bit[]=; for(int i=;i<=n;i++)bit[i]=bit[i>>]+;
  48. for(int j=;j<;j++)
  49. for(int i=;i<=n&&i+bin[j]-<=n;i++)
  50. ht[i][j]=min(ht[i][j-],ht[i+bin[j-]][j-]);
  51. }
  52. int getlcp(int x,int y)
  53. {
  54. if(x==y)return n-x+;
  55. x=rk[x]; y=rk[y];
  56. if(x>y)swap(x,y); x++;
  57. int w=bit[y-x+];
  58. return min(ht[x][w],ht[y-bin[w]+][w]);
  59. }
  60. void init()
  61. {
  62. for(int i=;i<=n;i++)
  63. sum[i]=sum[i-]+n-sa[i]+-ht[i][];
  64. }
  65. void find(ll x,int &st,int &len)
  66. {
  67. int l=,r=n,res;
  68. while(l<=r)
  69. {
  70. int mid=((l+r)>>);
  71. if(x>sum[mid-]&&x<=sum[mid]){res=mid; break;}//res:rk
  72. if(x<=sum[mid-])r=mid-;
  73. else l=mid+;
  74. }
  75. st=sa[res];//
  76. len=ht[res][]+x-sum[res-];
  77. }
  78. int cal(int st,int len)
  79. {
  80. int lst=n+,cnt=;//
  81. for(int i=n,lcp;i;i--)
  82. {
  83. if(rk[i]<rk[st])continue;
  84. if((lcp=getlcp(i,st))==)return K+;
  85. lcp=min(lcp,len);//
  86. if(lst>i&&lst<=i+lcp)continue;
  87. lst=i+; cnt++;
  88. }
  89. return cnt;
  90. }
  91. int main()
  92. {
  93. scanf("%d",&K); scanf("%s",s+); n=strlen(s+);
  94. for(int i=;i<=n;i++)dc[i]=(int)s[i],ch[i]=s[i];
  95. sort(dc+,dc+n+); m=unique(dc+,dc+n+)-dc-;
  96. for(int i=;i<=n;i++)s[i]=lower_bound(dc+,dc+m+,(int)s[i])-dc;
  97. work(); get(); init();
  98. ll l=,r=sum[n]; int pos=,ans=;
  99. while(l<=r)
  100. {
  101. ll mid=((l+r)>>1ll);
  102. int st,len; find(mid,st,len);
  103. if(cal(st,len)<=K)pos=st,ans=len,r=mid-;
  104. else l=mid+;
  105. }
  106. for(int i=pos;i<pos+ans;i++)putchar(ch[i]); puts("");
  107. return ;
  108. }

bzoj 4310 跳蚤 —— 后缀数组+二分答案+贪心的更多相关文章

  1. bzoj 4310 跳蚤——后缀数组+二分答案+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 答案有单调性? 二分出来一个子串,判断的时候需要满足那些字典序比它大的子串都不出现! ...

  2. BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案

    BZOJ_2946_[Poi2000]公共串_后缀数组+二分答案 Description          给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l        读入单 ...

  3. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  4. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

  5. 【bzoj4310】跳蚤 后缀数组+二分

    题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...

  6. 跳蚤[BZOJ4310](后缀数组+二分答案传判定)

    不知道后缀数组的请退回去! 题面: 题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S ...

  7. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

  8. BZOJ4310 跳蚤(后缀数组+二分答案)

    注意到答案一定是原串的子串,于是考虑造出SA,二分答案是第几小的子串.第k小子串很容易在SA上求出.之后计算使他成为最大子串至少要在几个位置切割,对每个字典序比答案大的后缀,找到所有合法切割位置(求l ...

  9. POJ3294--Life Forms 后缀数组+二分答案 大于k个字符串的最长公共子串

                                                                              Life Forms Time Limit: 500 ...

随机推荐

  1. hadoop修改主机名遇到的坑

    正确的修改方式 CentOS修改主机名(hostname) 需要修改两处:一处是/etc/sysconfig/network,另一处是/etc/hosts,只修改任一处会导致系统启动异常.首先切换到r ...

  2. firfox浏览器常用快捷键

    Ctrl + 数字键来打开第N个标签页这种还要先数完再到键盘上找数字Ctrl + Page Up = 激活左边一个标签页Ctrl + Page Down = 激活右边一个标签页Ctrl + Tab = ...

  3. iOS --生产JSON格式,创建JSON文件,创建文件夹,指定储存

    //生成json文件 - (void)onjson { //    如果数组或者字典中存储了  NSString, NSNumber, NSArray, NSDictionary, or NSNull ...

  4. urllib库python2和python3具体区别

      Python 2 name Python 3 name urllib.urlretrieve() urllib.request.urlretrieve() urllib.urlcleanup() ...

  5. PPID=1 runs as a background process, rather than being under the direct control of an interactive user

    https://en.wikipedia.org/wiki/Daemon_(computing) [后台进程,非互动] d 结尾 syslogd 系统日志记录 sshd 响应ssh连接请求 In mu ...

  6. Leslie Lamport

    http://lamport.azurewebsites.net/pubs/pubs.html paper

  7. mysql系列之2.mysql多实例

    使用场景 资金紧张; 并发访问不大; 门户网站; 实现 生产硬件配置: mem 32G / 双cpu 8核 / 磁盘6*600G sas 15k, 2-3个实例 安装组件 #yum install n ...

  8. django mysql setting 设置

    django mysql setting  django mysql 设置 DATABASES = {    'default': {        'ENGINE': 'django.db.back ...

  9. PAT 甲级 1065. A+B and C (64bit) (20) 【大数加法】

    题目链接 https://www.patest.cn/contests/pat-a-practise/1065 思路 因为 a 和 b 都是 在 long long 范围内的 但是 a + b 可能会 ...

  10. property 中的strong 与weak

    strong关键字与retain关似,用了它,引用计数自动+1,用实例更能说明一切 @property (nonatomic, strong) NSString *string1; @property ...