[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. IDEA安装Flutter遇到的坑

    环境: ①IDEA2019.3.3 ②JAVA12 ③Android-SDK29.0.3 ④Flutter1.14.6 ⑤WINDOWS10.0.18363.657 ⑥AL10实体机,Android8 ...

  2. 吴裕雄--天生自然HADOOP操作实验学习笔记:hbase的shell应用v2.0

    HRegion 当表的大小超过设置值的时候,HBase会自动地将表划分为不同的区域,每个区域包含所有行的一个子集.对用户来说,每个表是一堆数据的集合,靠主键来区分.从物理上来说,一张表被拆分成了多块, ...

  3. 【Debian学徒记事】Debian快速呼出Terminal终端

    Debian快速呼出Terminal终端 书接上回,Debian已经安装完毕 失踪的Ctrl+Alt+T 安装完毕启动,我发现了剑很诡异的事,Ctrl+Alt+T居然失灵了 (在多次测试后发现,Deb ...

  4. mysql引擎介绍

    mysql存储引擎介绍: 插拔式的插件方式 存储引擎是指定在表上的,即一个库中的每一个表都可以指定专用的存储引擎 不管采用什么样的存储引擎,都会在数据区产生对应的一个frm文件(表结构定义描述文件) ...

  5. tensorflow高阶操作

    本篇内容有:如何根据坐标有目的的选择(where).如何根据坐标有目的的更新(scatter_nd).如何生成一个坐标系() 1.where where针对的tensor是一个bool类型的tenso ...

  6. python之路(列表,元组)

    列表 list:基础数据类型之一,可以索引,切片,步长,切片+步长可以增删改查,可迭代,可嵌套字典,元组,列表 一.索引,切片,步长 list01 = [1,2,3,'eric','west'] 1. ...

  7. POJ1776(哈密顿路径)

    题目: http://poj.org/problem?id=1776 题意: 给出一个n*n的矩阵,若第i个任务做完之后可以做第j个任务,则矩阵的第i行第j列为1,否则为0.机器完成一项任务之后会自动 ...

  8. JAVA StringUtils工具类

    org.apache.commons.lang Class StringUtils java.lang.Object org.apache.commons.lang.StringUtils publi ...

  9. 扩展BSGS求解离散对数问题

    扩展BSGS用于求解axΞb mod(n) 同余方程中gcd(a,n)≠1的情况 基本思路,将原方程转化为a与n互质的情况后再套用普通的BSGS求解即可 const int maxint=((1< ...

  10. fastadmin选择下拉框

    fastadmin中要做下拉框的效果如下: 数据库中数据: 在对应model中添加一个方法: 控制器中添加一行: 在目录lang/zh-cn中找到你控制器名称所对应的文件添加配置: 在add.html ...