[BZOJ4310] 跳蚤

Description

首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 \(k\) 个子串中选择字典序最大的那一个。他称其为“魔力串”。现在他想找一个最优的分法让“魔力串”字典序最小。

Solution

我们将某个子串在所有子串(本质不同)中按照字典序的排名称作它的字典序排名。思考如何使用后缀数组快速求出一个子串的字典序排名。

假设我们要求 \(s[l,r]\) 这个子串的字典序排名,我们要在后缀排序中,从 \(r[l]\) 位置开始,向左找到第一个 \(h[i]<r-l+1\) 的位置,这个过程可以用二分 + ST表完成,那么 \(ra[i]-(n-sa[i]+1)+(r-l+1)\) 就是它的排名。

二分最终魔力串的字典序排名。我们倒着将整个串的字符一个个从前面插入,维护当前串的排名,如果当前串排名大于魔力串排名,那么这个当前串就危险了,我们要从它的第一个字符后面切开一刀。

这样我们只需要比较切的次数和 \(k\) 的关系,就可以调整二分边界。时间复杂度 \(O(nlogn)\)

我可真是个奥比啊 输出个方案挂了十几发

#include <bits/stdc++.h>
using namespace std; #define int long long
const int N = 200005; int n,m=256,sa[N],y[N],u[N],v[N],o[N],r[N],h[N],T,ra[N],Log2[N],lim,k,tbuf[N];
char str[N]; int rc=0; struct St {
int a[N][21];
void build(int *src,int n) {
for(int i=1;i<=n;i++) a[i][0]=src[i];
for(int i=1;i<=20;i++)
for(int j=1;j<=n-(1<<i)+1;j++)
a[j][i]=min(a[j][i-1],a[j+(1<<(i-1))][i-1]);
}
inline int query(int l,int r) {
int j=Log2[r-l+1];
return min(a[l][j],a[r-(1<<j)+1][j]);
}
} st; void generate_rank() {
for(int i=1;i<=n;i++) {
ra[i]=ra[i-1]+(n-sa[i]+1)-h[i];
}
} inline int bound(int l,int r,int v) {
while(r>l) {
int mid=(l+r)>>1;
if(st.query(mid+1,r)<v) l=mid+1;
else r=mid;;
}
return l;
} inline int getrank(int L,int R) {
int i=bound(1,r[L],R-L+1);
return ra[i]-(n-sa[i]+1)+(R-L+1);
} signed main(){ //freopen("inp.txt","r",stdin);
memset(str,0,sizeof str);
scanf("%lld%s",&k,str+1);
n=strlen(str+1); for(int i=1;i<=n;i++) Log2[i]=log2(i); for(int i=1;i<=n;i++) u[str[i]]++;
for(int i=1;i<=m;i++) u[i]+=u[i-1];
for(int i=n;i>=1;i--) sa[u[str[i]]--]=i;
r[sa[1]]=1;
for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]); for(int l=1;r[sa[n]]<n;l<<=1) {
memset(u,0,sizeof u);
memset(v,0,sizeof v);
memcpy(o,r,sizeof r);
for(int i=1;i<=n;i++) u[r[i]]++, v[r[i+l]]++;
for(int i=1;i<=n;i++) u[i]+=u[i-1], v[i]+=v[i-1];
for(int i=n;i>=1;i--) y[v[r[i+l]]--]=i;
for(int i=n;i>=1;i--) sa[u[r[y[i]]]--]=y[i];
r[sa[1]]=1;
for(int i=2;i<=n;i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l]));
}
{
int i,j,k=0;
for(int i=1;i<=n;h[r[i++]]=k)
for(k?k--:0,j=sa[r[i]-1];str[i+k]==str[j+k];k++);
} st.build(h,n); generate_rank(); lim=n*(n+1)/2;
for(int i=1;i<=n;i++) lim-=h[i]; int l=1,r=ra[n],al,aw;
while(r>l) {
int mid=(l+r)/2,se=n,cnt=0,tl,tw,tx=0;
for(int i=n;i>=1;--i) {
if(getrank(i,se)>mid) {
if(i==se) {
cnt=INT_MAX;
break;
}
++cnt;
se=i;
}
if(cnt>k) break;
}
++cnt;
if(cnt<=k) r=mid;
else l=mid+1;
}
ra[n+1]=INT_MAX;
for(int i=1;i<=n;i++) {
if(n-sa[i]+1 - h[i] >= l) {
for(int j=sa[i]; j<=sa[i]+h[i]+l-1; j++) printf("%c",str[j]);
return 0;
}
else l-=n-sa[i]+1-h[i];
}
}

[BZOJ4310] 跳蚤 - 后缀数组,二分,ST表的更多相关文章

  1. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  2. BZOJ3230 相似子串[后缀数组+二分+st表]

    BZOJ3230 相似子串 给一个串,查询排名i和j的子串longest common suffix和longest common prefix 思路其实还是蛮好想的,就是码起来有点恶心.可以发现后缀 ...

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

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

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

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 二分答案——在本质不同的子串中二分答案! 如果二分到的子串位置是 st,考虑何时必须分 ...

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

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

  6. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...

  7. [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析

    [BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...

  8. BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)

    Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...

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

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

随机推荐

  1. pytest文档32-allure描述用例详细讲解

    前言 pytest+allure是最完美的结合了,关于allure的使用,本篇做一个总结. allure报告可以很多详细的信息描述测试用例,包括epic.feature.story.title.iss ...

  2. jQuery---小火箭返回顶部案例

    小火箭返回顶部案例 1. 滚动页面,当页面距离顶部超出1000px,显示小火箭. 封装在scroll函数里,当前页面距离顶部为$(window).scrollTop >=1000 小火箭显示和隐 ...

  3. Python集合详解

    集合介绍: 集合(set)是一个无序的不重复元素序列.可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典 ...

  4. python 3.6 安装 opencv 3.4

    一种说法是,到opencv官网下载相应的版本opencv,解压,把cv2.pyd放到 python安装文件夹下的\Lib\site-packages里即可, 此时import cv2即可成功 我的没有 ...

  5. 小白的java学习之路 “ 循环结构(二)”

    一.for 循环 语法: for(表达式一;表达式二;表达式三){ 循环操作 } 表达式一:参数初始化 表达式二:条件判断 表达式三:更新循环变量 执行流程: 步骤一:执行表达式一.初始化参数 步骤二 ...

  6. 构造并判断二叉搜索树-js

    class Node { constructor (val) { this.val = val this.left = this.right = undefined } } class Tree { ...

  7. 【spring boot】SpringBoot初学(7)– 多数据源及其事务

    前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...

  8. 开学第一课Java考试

    package moguiba;import java.text.DecimalFormat;import java.util.Scanner;import moguiba.ScoreInformat ...

  9. 收录了老师发的几个 download ebook and paper 的 webpage

    Library Genesis (important) http://zh.b-ok.org National Academic Press OpenStax CNX gen.lib.rus.ec l ...

  10. NOI Online能力测试游记:退役选手的自娱自乐

    2020年2月17日早上8点,CCF发布了关于举办NOI Online能力测试的通知. 为给选手提供一个锻炼的机会,CCF拟举办一场NOI Online能力测试.测试分为入门组和提高组,每组限额报名3 ...