我真的是。。调了一百年。。

傻逼的人生。。

而且这题好像可以用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-跳蚤】后缀数组的更多相关文章

  1. 【BZOJ-4310】跳蚤 后缀数组 + ST表 + 二分

    4310: 跳蚤 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 180  Solved: 83[Submit][Status][Discuss] De ...

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

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

  3. [BZOJ4310] 跳蚤 - 后缀数组,二分,ST表

    [BZOJ4310] 跳蚤 Description 首先,他会把串分成不超过 \(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. BZOJ4310: 跳蚤 【后缀数组+二分】

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

  7. 跳蚤[BZOJ4310](后缀数组+二分答案传判定)

    不知道后缀数组的请退回去! 题面: 题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究.首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S ...

  8. bzoj 4310 跳蚤 二分答案+后缀数组/后缀树

    题目大意 给定\(k\)和长度\(\le10^5\)的串S 把串分成不超过\(k\)个子串,然后对于每个子串\(s\),他会从\(s\)的所有子串中选择字典序最大的那一个,并在选出来的\(k\)个子串 ...

  9. 后缀数组 hash求LCP BZOJ 4310: 跳蚤

    后缀数组的题博客里没放进去过..所以挖了一题写写 充实下博客 顺便留作板子.. 一个字符串S中 内容不同的子串 有 sigma{n-sa[i]+1-h[i]}   (噢 这里的h[]就是大家熟知的he ...

随机推荐

  1. Hibernate-ORM:11.Hibernate中的关联查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(i ...

  2. Python全栈 MongoDB 数据库(数据的修改)

    修改操作符的使用   $set 修改一个域的值,增加一个域   阿哲年龄修改为33 db.class1.update({name:'阿哲'},{$set:{age:33}})   如果sex域不存在则 ...

  3. [CH5302]金字塔

    题面 虽然探索金字塔是极其老套的剧情,但是有一队探险家还是到了某金字塔脚下.经过多年的研究,科学家对这座金字塔的内部结构已经有所了解.首先,金字塔由若干房间组成,房间之间连有通道.如果把房间看作节点, ...

  4. SSH 项目中 使用websocket 实现网页聊天功能

    参考文章  :java使用websocket,并且获取HttpSession,源码分析    http://www.cnblogs.com/zhuxiaojie/p/6238826.html 1.在项 ...

  5. 虚拟机CentOS7.2 1611 Minimal最小化安装后桥接固定ip

    ip addr show 或者 ip addr 或者 ip a vim /etc/sysconfig/network-scripts/ifcfg-ens33 根据 然后重启网卡 service net ...

  6. linux下搜索find命令拾遗

    强制删除项目下面的所有.svn文件目录,find . -name ‘.svn’ -exec rm -rf {} \; empty显示所有的空白文件,并显示详细:find . -empty size显示 ...

  7. Thread.currentThread().getContextClassLoader().loadClass(className)和Class.forName(className)的区别

    一.正文: 有去看开源框架的童鞋,应该会经常看到如下代码:Thread.currentThread().getContextClassLoader().loadClass(className),那这个 ...

  8. Eclipse中构建scala开发环境的步骤

    Eclipse是一款非常使用的开发工具,熟悉它的童鞋应该都知道,它不仅是最常用的android开发工具,还是最常用的Java开发工具.既然eclipse如此重要,本文小编就和大家一起来扒一扒在ecli ...

  9. P2874 [USACO07FEB]新牛棚Building A New Barn

    题目描述 After scrimping and saving for years, Farmer John has decided to build a new barn. He wants the ...

  10. 51nod 1819 黑白树V2(树链剖分)

    第一次写如此复杂的树链剖分, 感觉自己代码能力还是挺不错的,没有调试太久(2个小时) 最后代码量高达11K orz(大部分都是重复的线段树代码,以后可以考虑优化一下代码量) 题解: 首先就是要进行一次 ...