【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分
4310: 跳蚤
Time Limit: 20 Sec Memory Limit: 512 MB
Submit:
180 Solved: 83
[Submit][Status][Discuss]
Description
个子串中选择字典序最大的那一个。他称其为“魔力串”。
Input
Output
Sample Input
bcbcbacbbbbbabbacbcbacbbababaabbbaabacacbbbccaccbcaabcacbacbcabaacbccbbcbcbacccbcccbbcaacabacaaaaaba
Sample Output
HINT
Source
Solution
首先求出后缀数组和height数组,这样能得到本质不同的子串数目
这里利用:本质不同的子串$=\sum(Len-SA[i]-height[i])$利用SA[],height[]的定义很好想
然后要求最大值最小,显然二分,二分一个mid,求出第mid大的子串
然后贪心的检验,从后往前扫,当字典序超过二分的值时,划分一下,看划分个数与K的关系即可
中间涉及比较,用LCP实现即可,显然ST表非常方便
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 1000100
char S[maxn]; int SA[maxn],len,K;
int wa[maxn],wb[maxn],ws[maxn],wv[maxn];
long long tot;
int L,R;
inline int cmp(int *r,int a,int b,int l)
{
return r[a]==r[b]&&r[a+l]==r[b+l];
}
inline void DA(char *r,int *sa,int n,int m)
{
int p,*x=wa,*y=wb,*t;
for (int i=; i<m; i++) ws[i]=;
for (int i=; i<n; i++) ws[x[i]=r[i]]++;
for (int i=; i<m; i++) ws[i]+=ws[i-];
for (int i=n-; i>=; i--) sa[--ws[x[i]]]=i;
p=; for (int j=; p<n; j*=,m=p)
{
p=; for (int i=n-j; i<n; i++) y[p++]=i;
for (int i=; i<n; i++) if (sa[i]>=j) y[p++]=sa[i]-j;
for (int i=; i<n; i++) wv[i]=x[y[i]];
for (int i=; i<m; i++) ws[i]=;
for (int i=; i<n; i++) ws[wv[i]]++;
for (int i=; i<m; i++) ws[i]+=ws[i-];
for (int i=n-; i>=; i--) sa[--ws[wv[i]]]=y[i];
t=x,x=y,y=t;p=;x[sa[]]=;
for (int i=; i<n; i++)
x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
}
}
int rank[maxn],height[maxn];
inline void calheight(char *r,int *sa,int n)
{
int k=;
for (int i=; i<=n; i++) rank[sa[i]]=i;
for (int i=; i<n; height[rank[i++]]=k)
{k?k--:;for (int j=sa[rank[i]-]; r[i+k]==r[j+k]; k++);}
}
int log2[maxn]; int dp[maxn][];
void ST(int n)
{
log2[]=-;
for (int i=; i<=n; i++)
if (i&(i-)) log2[i]=log2[i-];
else log2[i]=log2[i-]+;
for (int i=; i<=n; i++) dp[i][]=height[i];
for (int j=; (<<j)<=len; j++)
for (int i=; i+(<<j)-<=n; i++)
dp[i][j]=min(dp[i][j-],dp[i+(<<(j-))][j-]);
}
int RMQ(int l,int r)
{
int tmp=log2[r-l+];
return min(dp[l][tmp],dp[r-(<<tmp)+][tmp]);
}
int LCP(int l,int r)
{
if (l==r) return len-l;
l=rank[l]; r=rank[r];
if (l>r) swap(l,r); l++;
return RMQ(l,r);
}
void Get(long long k)
{
for (int i=; i<=len; i++)
if ((long long)(len-SA[i]-height[i])<k) k-=(long long)(len-SA[i]-height[i]);
else {L=SA[i],R=SA[i]+height[i]+k-; break;}
}
bool Compare(int l1,int r1,int l2,int r2)
{
int len1=r1-l1+,len2=r2-l2+,lcp=LCP(l1,l2);
if (len1<=len2 && lcp>=len1) return ;
if (len1>len2 && lcp>=len2) return ;
if (lcp>=len1 && lcp>=len2) return len1>len2? :;
return S[l1+lcp]>S[l2+lcp]? :;
}
int Check()
{
int cnt=,last=len-;
for (int i=len-; i>=; i--)
{
if (S[i]>S[L]) return ;
if (!Compare(i,last,L,R)) ++cnt,last=i;
if (cnt>K) return ;
}
return ;
}
int main()
{
scanf("%d",&K); scanf("%s",S);
len=strlen(S); S[len]=;
DA(S,SA,len+,); calheight(S,SA,len);
ST(len);
for (int i=; i<=len; i++) tot+=len-SA[i]-height[i];
// printf("%d\n",tot);
long long l=,r=tot;
while (l<=r)
{
long long mid=(l+r)>>;
Get(mid);
// printf("L=%d R=%d\n",L,R);
if (Check()) r=mid-; else l=mid+;
// printf("%I64d %I64d\n",l,r);
}
Get(r+);
for (int i=L; i<=R; i++) putchar(S[i]);
return ;
}
【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分的更多相关文章
- 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)
题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...
- bzoj 4310: 跳蚤【后缀数组+st表+二分+贪心】
先求一下SA 本质不同的子串个数是\( \sum n-sa[i]+1-he[i] \),按字典序二分子串,判断的时候贪心,也就是从后往前扫字符串,如果当前子串串字典序大于二分的mid子串就切一下,然后 ...
- bzoj 4310 跳蚤 —— 后缀数组+二分答案+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 二分答案——在本质不同的子串中二分答案! 如果二分到的子串位置是 st,考虑何时必须分 ...
- bzoj 4310 跳蚤——后缀数组+二分答案+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 答案有单调性? 二分出来一个子串,判断的时候需要满足那些字典序比它大的子串都不出现! ...
- SPOJ 687 Repeats(后缀数组+ST表)
[题目链接] http://www.spoj.com/problems/REPEATS/en/ [题目大意] 求重复次数最多的连续重复子串的长度. [题解] 考虑错位匹配,设重复部分长度为l,记s[i ...
- POJ 3693 Maximum repetition substring(后缀数组+ST表)
[题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+ ...
- BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay
BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔 ...
- UVA10829 L-Gap Substrings(后缀数组+ST表)
后缀数组+ST表. 代填的坑. \(Code\ Below:\) #include <bits/stdc++.h> #define ll long long using namespace ...
- BZOJ 4556 [Tjoi2016&Heoi2016]字符串 ——后缀数组 ST表 主席树 二分答案
Solution 1: 后缀数组暴力大法好 #include <map> #include <cmath> #include <queue> #include &l ...
随机推荐
- iOS十六进制和字符串的相互转换
转换代码,崩溃日志有些是十六进制 NSString *dictString = [dict JSONFragment];//组合成的 dictString==={"content" ...
- 根据Unicode编码用C#语言把它转换成汉字的代码
rt 根据所具有的Unicode编码用C#语言把它转换成汉字的代码 var s = System.Web.HttpUtility.HtmlDecode(Utf8Str); var o = Newton ...
- BZOJ 1010 【HNOI2008】 玩具装箱toy
Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1... ...
- 折腾了1周把程序从sqlserver迁移到oracle上了,每折腾一次需要耗费1周时间
主要花费时间的事情: 1:安装配套的服务器,安装操作系统,安装数据库,配置远程访问等等,一般会耗费1天时间,甚至2天时间,若手头安装盘不齐全,需要耗费更多时间. 2:远程传输安装文件.特别是开发环境等 ...
- C++变量命名规则
转自:http://www.cnblogs.com/finallyliuyu/archive/2010/09/25/1834301.html 浅谈C++变量命名规则 不知道别的公司如何,反正我现在的公 ...
- Asp.net WebApi Put模式调用,“HTTP 错误 405.0 - Method Not Allowed”解决方法
IIS10.0在部署了WebAPI之后,默认是不支持Put模式调用的.需要按照下面方法启用. 步骤一:在IIS管理界面要支持Put模式的IIS站点,选择 "功能视图". 步骤二:选 ...
- lecture14-RBM的堆叠、修改以及DBN的决策学习和微调
这是Hinton的第14课,主要介绍了RBM和DBN的东西,这一课的课外读物有三篇论文<Self-taught learning- transfer learning from unlabele ...
- 深入理解OOP(三):多态和继承(动态绑定和运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...
- xml序列化及反序列化.net对象
序列化一个类通常添加[XmlRoot("根节点名字")] 找到要序列化的内容 对要序列化的类添加 [Serializable]属性用于序列化 对于要序列化的字段添加 [XmlEl ...
- [HDOJ5451]Best Solver(乱搞)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5451 分析:A=5+2根号6 B=6-2根号6 n=1+2^x 那么A^n+B^n是整数 注意到0< ...