题意:

给出一个字符串,至多将其划分为n部分,每一部分取出字典序最大的子串ci,最小化 最大的ci

先看一个简化版的问题:

给一个串s,再给一个s的子串t,问能否通过将串划分为k个部分,使t成为划分后的s的字典序最大子串

 
对于这个问题,从串s的最后面开始,一个字符一个字符的向前推
如果当前[l,r]字典序比t大,那么[l+1,r]就要单独成为一段
比较子串字典序大小用二分+哈希
因为我们是一个字符一个字符的向前推的,所以一定是新的l使当前[l,r]字典序比t大
所以如果此时l==r,那么这个t不可能成为字典序最大子串
如果最后部分数<=k,则这个t可以
 
那么本题只需要二分子串t就好了
所以现在问题变成如何获取字典序 排名第k的子串
这个可以通过后缀数组的height求出
[sa[1],sa[1]] 是字典序第1小
[sa[1],sa[1]+1]是字典序第2小
……
[sa[1],n]是字典序第n-sa[1]+1 小
[sa[2],sa[2]+height[2]] 是下一个
再下一个是 [sa[2],sa[2]+height[2]+1]
…… 
 
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4.  
  5. using namespace std;
  6.  
  7. #define N 100001
  8.  
  9. typedef long long LL;
  10.  
  11. const int base=;
  12.  
  13. int n,m;
  14. char s[N];
  15.  
  16. int a[N];
  17. int v[N];
  18. int p,q=,k;
  19. int sa[][N],rk[][N];
  20. int h[N];
  21.  
  22. unsigned long long Pow[N],has[N];
  23.  
  24. pair<int,int>interval[N];
  25.  
  26. void mul(int *sa,int*rk,int *SA,int *RK)
  27. {
  28. for(int i=;i<=n;++i) v[rk[sa[i]]]=i;
  29. for(int i=n;i;--i) if(sa[i]>k) SA[v[rk[sa[i]-k]]--]=sa[i]-k;
  30. for(int i=n-k+;i<=n;++i) SA[v[rk[i]]--]=i;
  31. for(int i=;i<=n;++i) RK[SA[i]]=RK[SA[i-]]+(rk[SA[i]]!=rk[SA[i-]] || rk[SA[i]+k]!=rk[SA[i-]+k]);
  32. }
  33.  
  34. void presa()
  35. {
  36. for(int i=;i<=n;++i) v[a[i]]++;
  37. for(int i=;i<=;++i) v[i]+=v[i-];
  38. for(int i=;i<=n;++i) sa[p][v[a[i]]--]=i;
  39. for(int i=;i<=n;++i) rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i]]!=a[sa[p][i-]]);
  40. for(k=;k<n;k<<=,swap(p,q)) mul(sa[p],rk[p],sa[q],rk[q]);
  41. }
  42.  
  43. void get_height()
  44. {
  45. int j,k=;
  46. for(int i=;i<=n;++i)
  47. {
  48. j=sa[p][rk[p][i]-];
  49. while(a[i+k]==a[j+k]) k++;
  50. h[rk[p][i]]=k;
  51. if(k) k--;
  52. }
  53. }
  54.  
  55. void prehash()
  56. {
  57. Pow[]=;
  58. for(int i=;i<=n;++i) Pow[i]=Pow[i-]*base;
  59. for(int i=;i<=n;++i) has[i]=has[i-]*base+a[i];
  60. }
  61.  
  62. pair<int,int>select(LL k)
  63. {
  64. int now;
  65. LL sum=;
  66. int l,r;
  67. for(int i=;i<=n;++i)
  68. {
  69. now=interval[i].second-interval[i].first+;
  70. if(sum+now>=k)
  71. {
  72. l=sa[p][i];
  73. r=interval[i].first+k-sum-;
  74. return make_pair(l,r);
  75. }
  76. sum+=now;
  77. }
  78. }
  79.  
  80. unsigned long long get_hash(int l,int r)
  81. {
  82. return has[r]-has[l-]*Pow[r-l+];
  83. }
  84.  
  85. int cmp(pair<int,int>x,pair<int,int>y)
  86. {
  87. if(get_hash(x.first,x.second)==get_hash(y.first,y.second)) return ;
  88. int Lx=x.second-x.first+,Ly=y.second-y.first+;
  89. int l=,r=min(Lx,Ly),mid,tmp=;
  90. while(l<=r)
  91. {
  92. mid=l+r>>;
  93. if(get_hash(x.first,x.first+mid-)==get_hash(y.first,y.first+mid-)) tmp=mid,l=mid+;
  94. else r=mid-;
  95. }
  96. if(tmp<min(Lx,Ly)) return s[x.first+tmp]<s[y.first+tmp] ? - : ;
  97. return Lx<Ly ? - : ;
  98. }
  99.  
  100. bool check(pair<int,int>now)
  101. {
  102. int l=n,r=n,sum=;
  103. while(l>=)
  104. if(cmp(make_pair(l,r),now)==)
  105. {
  106. if(l==r) return false;
  107. r=l;
  108. sum++;
  109. if(sum>m) return false;
  110. }
  111. else l--;
  112. return true;
  113. }
  114.  
  115. void solve()
  116. {
  117. LL l=,r=;
  118. for(int i=;i<=n;++i)
  119. {
  120. interval[i].first=sa[p][i]+h[i];
  121. interval[i].second=n;
  122. r+=interval[i].second-interval[i].first+;
  123. }
  124. LL mid,tmp;
  125. pair<int,int>now;
  126. while(l<=r)
  127. {
  128. mid=l+r>>;
  129. now=select(mid);
  130. if(check(now)) tmp=mid,r=mid-;
  131. else l=mid+;
  132. }
  133. now=select(tmp);
  134. l=now.first; r=now.second;
  135. for(int i=l;i<=r;++i) putchar(s[i]);
  136. }
  137.  
  138. int main()
  139. {
  140. freopen("string.in","r",stdin);
  141. freopen("string.out","w",stdout);
  142. scanf("%d",&m);
  143. scanf("%s",s+);
  144. n=strlen(s+);
  145. for(int i=;i<=n;++i) a[i]=s[i]-'a'+;
  146. presa();
  147. get_height();
  148. prehash();
  149. solve();
  150. }

2016vijos 1-1 兔子的字符串(后缀数组 + 二分 + 哈希)的更多相关文章

  1. 【BZOJ-4556】字符串 后缀数组+二分+主席树 / 后缀自动机+线段树合并+二分

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 657  Solved: 274[Su ...

  2. 【BZOJ4556】[Tjoi2016&Heoi2016]字符串 后缀数组+二分+主席树+RMQ

    [BZOJ4556][Tjoi2016&Heoi2016]字符串 Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一 ...

  3. 【BZOJ3277/3473】串/字符串 后缀数组+二分+RMQ+双指针

    [BZOJ3277]串 Description 字符串是oi界常考的问题.现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Inpu ...

  4. POJ 2774 后缀数组 || 二分+哈希

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 35607   Accepted: 14 ...

  5. BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案

    Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...

  6. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

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

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

  8. POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)

    洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...

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

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

随机推荐

  1. nginx+php使用open_basedir限制站点目录防止跨站

    以下三种设置方法均需要PHP版本为5.3或者以上.方法1)在Nginx配置文件中加入 fastcgi_param PHP_VALUE "open_basedir=$document_root ...

  2. hiho1258 Osu! Master

    题目链接:http://hihocoder.com/problemset/problem/1258 题目大意:看能连击的次数 思路:水 看有多少个1和s就好了 #include <stdio.h ...

  3. 从App业务逻辑中提炼API接口

    2.1 从App业务逻辑中提炼API接口 业务逻辑思维导图 功能-业务逻辑思维导图 基本功能模块关系 功能模块接口UML(设计出API) 在设计稿标注API 编写API文档 2.2 设计API的要点 ...

  4. 「SPOJ6340」「BZOJ1939」ZUMA - ZUMA【记忆化搜索】

    题目链接 [洛谷传送门] 题解 \(f[i][j][k]\)表示在消除了\((i,j)\),在后面加上了\(k\)个珠子的总的珠子数. 考虑三种决策:(题目给出的\(k\)在下文表示成\(K\)) 决 ...

  5. 「洛谷1903」「BZOJ2120」「国家集训队」数颜色【带修莫队,树套树】

    题目链接 [BZOJ传送门] [洛谷传送门] 题目大意 单点修改,区间查询有多少种数字. 解法1--树套树 可以直接暴力树套树,我比较懒,不想写. 稍微口胡一下,可以直接来一个树状数组套主席树,也就是 ...

  6. [HNOI2010]物品调度

    题目描述 现在找工作不容易,Lostmonkey费了好大劲才得到fsk公司基层流水线操作员的职位.流水线上有n个位置,从0到n-1依次编号,一开始0号位置空,其它的位置i上有编号为i的盒子.Lostm ...

  7. 在linux环境下搭建JDK+JAVA+Mysql,并完成jforum的安装

    参考链接: YUM安装MySQL和JDK和Tomcat:http://cmdschool.blog.51cto.com/2420395/1696206/ http://www.cnblogs.com/ ...

  8. 阻止 form 回车 自动提交

    问题:当form表单中只有一个input时,在input中按回车键会自动提交. 解决方案: 1.form元素上加onsubmit="return false"(推荐) 2.多个in ...

  9. 每天一个Linux命令 (转)

    一. 文件目录操作命令: 1.每天一个linux命令(1):ls命令 2.每天一个linux命令(2):cd命令  3.每天一个linux命令(3):pwd命令 4.每天一个linux命令(4):mk ...

  10. 团体程序设计天梯赛(CCCC) L3014 周游世界 BFS证明

    团体程序设计天梯赛代码.体现代码技巧,比赛技巧.  https://github.com/congmingyige/cccc_code