【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 ...
随机推荐
- Hibernate-ORM:11.Hibernate中的关联查询
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(i ...
- Python全栈 MongoDB 数据库(数据的修改)
修改操作符的使用 $set 修改一个域的值,增加一个域 阿哲年龄修改为33 db.class1.update({name:'阿哲'},{$set:{age:33}}) 如果sex域不存在则 ...
- [CH5302]金字塔
题面 虽然探索金字塔是极其老套的剧情,但是有一队探险家还是到了某金字塔脚下.经过多年的研究,科学家对这座金字塔的内部结构已经有所了解.首先,金字塔由若干房间组成,房间之间连有通道.如果把房间看作节点, ...
- SSH 项目中 使用websocket 实现网页聊天功能
参考文章 :java使用websocket,并且获取HttpSession,源码分析 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 1.在项 ...
- 虚拟机CentOS7.2 1611 Minimal最小化安装后桥接固定ip
ip addr show 或者 ip addr 或者 ip a vim /etc/sysconfig/network-scripts/ifcfg-ens33 根据 然后重启网卡 service net ...
- linux下搜索find命令拾遗
强制删除项目下面的所有.svn文件目录,find . -name ‘.svn’ -exec rm -rf {} \; empty显示所有的空白文件,并显示详细:find . -empty size显示 ...
- Thread.currentThread().getContextClassLoader().loadClass(className)和Class.forName(className)的区别
一.正文: 有去看开源框架的童鞋,应该会经常看到如下代码:Thread.currentThread().getContextClassLoader().loadClass(className),那这个 ...
- Eclipse中构建scala开发环境的步骤
Eclipse是一款非常使用的开发工具,熟悉它的童鞋应该都知道,它不仅是最常用的android开发工具,还是最常用的Java开发工具.既然eclipse如此重要,本文小编就和大家一起来扒一扒在ecli ...
- P2874 [USACO07FEB]新牛棚Building A New Barn
题目描述 After scrimping and saving for years, Farmer John has decided to build a new barn. He wants the ...
- 51nod 1819 黑白树V2(树链剖分)
第一次写如此复杂的树链剖分, 感觉自己代码能力还是挺不错的,没有调试太久(2个小时) 最后代码量高达11K orz(大部分都是重复的线段树代码,以后可以考虑优化一下代码量) 题解: 首先就是要进行一次 ...