【bzoj4310/hdu5030-跳蚤】后缀数组
我真的是。。调了一百年。。
傻逼的人生。。
而且这题好像可以用sam做哎!我Y出了一个奇怪的办法。。
好吧sam是不能做这题的。搞错了。
说说后缀数组好了。。
搞后缀数组
然后我们要二分一个子串,判断是否有一种划分方法,满足划分出来的所有串的最大子串不超过这个串。
二分是第now个后缀
二分第now个多长的前缀
————确定了一个子串
首先,这题具有单调性,而且是求最大串最小,所以我们可以二分答案串。
怎么二分答案串呢,我们不是已经用后缀数组求出了sa数组吗,sa数组表示的串是排过序的,其中每个后缀的前缀子串大小按长度的递增而递增,所以可以在sa数组里面二分。(我是先二分后缀,再二分长度)然后是判断,怎么判断是不是可以划分成至多k个串使他们都不超过二分串。还是在sa上做。如果他的sa位置小于mid,那么不用管,因为它怎么样都是小于二分串的。如果他的sa位置大于等于mid,而且他跟二分串没有LCP,那么这个二分一定没有答案,因为最小二分都使他不符合。除此之外,求出sa位置大于等于mid的所有串跟二分串的LCP,在sa[i]~sa[i]+lcp-1的位置上一定要至少打一个标记,因为不打标记它就会比二分串大了。所以最后我们会得到很多个区间,在这些区间里面至多打k-1个标记,使得每个区间中有含有一个标记。转化成了这样,就很容易做了。貌似是smg区间覆盖之类的问题。排个序,去个重,判断+累加一下就可以了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std; const int N=,Inf=(int)1e9;
int K,n,cl,ed,r[N],h[N],t[N],rk[N],Rs[N],sa[N],y[N],wr[N];
char c[N]; int minn(int x,int y){return x<y ? x:y;} void get_sa(int m)
{
for(int i=;i<=cl;i++) rk[i]=c[i]-'a'+;
for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[rk[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[rk[i]]--]=i;//debug int ln=,p=;
while(p<cl)
{
int k=;
for(int i=cl-ln+;i<=cl;i++) y[++k]=i;
for(int i=;i<=cl;i++)
if(sa[i]>ln) y[++k]=sa[i]-ln;
for(int i=;i<=cl;i++) wr[i]=rk[y[i]]; for(int i=;i<=m;i++) Rs[i]=;
for(int i=;i<=cl;i++) Rs[wr[i]]++;
for(int i=;i<=m;i++) Rs[i]+=Rs[i-];
for(int i=cl;i>=;i--) sa[Rs[wr[i]]--]=y[i];//debug for(int i=;i<=cl;i++) wr[i]=rk[i];
for(int i=cl+;i<=cl+ln;i++) wr[i]=;
rk[sa[]]=;
p=;
for(int i=;i<=cl;i++)
{
if(wr[sa[i]]!=wr[sa[i-]] || wr[sa[i]+ln]!=wr[sa[i-]+ln]) p++;
rk[sa[i]]=p;
}
ln*=;m=p;
// for(int i=1;i<=cl;i++) printf("%d ",rk[i]);printf("\n");
// for(int i=1;i<=cl;i++) printf("%d ",sa[i]);printf("\n");
}
sa[]=rk[]=;
} void get_h()
{
int k=;
for(int i=;i<=cl;i++) if(rk[i]!=)
{
int j=sa[rk[i]-];
if(k) k--;
while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++;
h[rk[i]]=k;
}
h[]=;
} bool ok(int ll,int rr)
{
int k=rr-ll+;
memset(t,,sizeof(t));
memset(r,,sizeof(r));
for(int i=rk[ll];i<=cl;i++)
{
if(i!=rk[ll]) k=minn(k,h[i]);
else if(rr==cl) continue;
if(k==) return ;
if(t[sa[i]]== || sa[i]+k-<t[sa[i]]) t[sa[i]]=sa[i]+k-;
}
int pl=,pr=,cut,ans;
for(int i=cl;i>=;i--)
{
if(!t[i]) continue;
if(!pr) {pr=i;continue;}
if(pr<=t[i]) t[i]=;
pr=t[i];
}
for(int i=;i<=cl;i++) if(t[i]) r[t[i]]=i;
pl=,pr=,cut=,ans=;
for(int i=cl;i>=;i--)
{
if(!r[i]) continue;
if(!pl) {pl=r[i],pr=i;cut=r[i];ans++;continue;}
if(i<pl) cut=r[i],ans++;
if(pl<=i && i<=pr)
{
if(!(cut>=r[i] && cut<=i)) cut=r[i],ans++;
}
pl=r[i],pr=i;
}
if(ans<=K-) return ;
return ;
} int check(int now)
{
int ll=sa[now]+h[now],rr=cl,mid;
while(ll<=rr)
{
mid=(ll+rr)/;
if(ok(sa[now],mid))
{
rr=mid;
if(ll==rr) return ll;
}
else ll=mid+;
}
if(ll<=rr) return ll;
return ;
} int main()
{
// freopen("a.in","r",stdin);
freopen("magic.in","r",stdin);
freopen("magic.out","w",stdout);
scanf("%d",&K);
scanf("%s",c+);
cl=strlen(c+);
get_sa();
get_h();
int ll=,rr=cl,mid,now;
while(ll<rr)
{
mid=(ll+rr)/;
now=check(mid);
if(now) rr=mid,ed=now;
else ll=mid+;
}
if(ll)
{
for(int i=sa[ll];i<=ed;i++) printf("%c",c[i]);printf("\n");
}
return ;
}
贴一下代码啦。
【bzoj4310/hdu5030-跳蚤】后缀数组的更多相关文章
- 【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分
4310: 跳蚤 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 180 Solved: 83[Submit][Status][Discuss] De ...
- 【bzoj4310】跳蚤 后缀数组+二分
题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...
- [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表
[BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(k\) 个子串,然后对于每个子串 \(S\) ,他会从 \(S\) 的所有子串中选择字典序最大的那一个,并在选出来的 ...
- bzoj 4310 跳蚤 —— 后缀数组+二分答案+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 二分答案——在本质不同的子串中二分答案! 如果二分到的子串位置是 st,考虑何时必须分 ...
- bzoj 4310 跳蚤——后缀数组+二分答案+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4310 答案有单调性? 二分出来一个子串,判断的时候需要满足那些字典序比它大的子串都不出现! ...
- BZOJ4310: 跳蚤 【后缀数组+二分】
Description 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串 分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典 ...
- 跳蚤[BZOJ4310](后缀数组+二分答案传判定)
不知道后缀数组的请退回去! 题面: 题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S ...
- bzoj 4310 跳蚤 二分答案+后缀数组/后缀树
题目大意 给定\(k\)和长度\(\le10^5\)的串S 把串分成不超过\(k\)个子串,然后对于每个子串\(s\),他会从\(s\)的所有子串中选择字典序最大的那一个,并在选出来的\(k\)个子串 ...
- 后缀数组 hash求LCP BZOJ 4310: 跳蚤
后缀数组的题博客里没放进去过..所以挖了一题写写 充实下博客 顺便留作板子.. 一个字符串S中 内容不同的子串 有 sigma{n-sa[i]+1-h[i]} (噢 这里的h[]就是大家熟知的he ...
随机推荐
- LeetCode:17. Letter Combinations of a Phone Number(Medium)
1. 原题链接 https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/ 2. 题目要求 给定一 ...
- ASCII码、HEX、字符、BCD 等等 基础知识思考
每每遇到这些问题就要想个半天,想不明白还不舒服,今天特别把所想整理下避免以后再次进入思想漩涡!!! 计算机存储和传输都是以字节为单位 1 bit = 1 二进制数据 ...
- 步骤2:JMeter 分布式测试(性能测试大并发、远程启动解决方案)
转载(记录) http://www.cnblogs.com/fengpingfan/p/5583954.html http://www.cnblogs.com/puresoul/p/4844539.h ...
- Java Set集合(HashSet、TreeSet)
什么是HashSet?操作过程是怎么样的? 1.HashSet底层实际上是一个HashMap,HashMap底层采用了哈希表数据结构 2.哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素 ...
- 关于Vue脚手架写法的问题
问题描述: main.js import Vue from 'vue' import App from './App' /* eslint-disable no-new */ new Vue({ el ...
- 《python核心编程第二版》第8章习题
8–1. 条件语句. 请看下边的代码 # statement Aif x > 0:# statement Bpasselif x < 0:# statement Cpasselse:# s ...
- 7.0 启动app权限弹窗问题
这里提供两种解决方案! 1.安卓6.0+是可以直接利用uiautomator定位元素点击!这个不细说,定位方式很多种...这个等待时间大家自己定大概两到三秒即可! #安卓6.0+点击方式driver. ...
- web3无法安装的额解决方案-----yarn命令安装web3
凡是可以用 JavaScript 来写的应用,最终都会用 JavaScript 来写. --Atwood定律(Jeff Atwood在2007年提出) yarn命令详解 https://yarnpkg ...
- CSS设计指南之伪类
伪类这个叫法源自它们与类相似,但实际上并没有类会附加到标记中的标签上.伪类分两种. UI伪类会在HTML元素处于某个状态时(比如鼠标指针位于链接上),为该元素应用CSS样式. 结构化伪类会在标记中存在 ...
- Java面试题-字符串操作
题目:输入一行字符,分别统计出其中英文字母,空格,数字和其他字符个数 //创建一个容器,用来保存结果,英文字母空格数组和其他字符做key,个数为value Map<String,Integer& ...