题意

大概就是给你一个串,对于每个\(i\),在\([1,i-1]\)中找到一个\(j\),使得\(lcp(i,j)\)最长,若有多个最大\(j\)选最小,求\(j\)和这个\(lcp\)长度

思路

首先我们需要知道对于每个\(i\),能与下标小于\(i\)开头的前缀构成的最大\(lcp\)是多少

这个可以在最外层枚举\(i\)的过程中维护一个\(set\),这样在插入当前的\(rk[i]\)的时候能\(O(logn)\)得到这个最长的\(lcp\)

然后根据这个值二分出\(rk[i]\)向左右能扩展的最远的地方\([L,R]\),使得\(lcp\)依然为这个值

\([L,R]\)内的最小的\(sa\)就是答案

脑子抽了用了个线段树维护已经存在过的下标,没出现的用\(inf\)表示,但实际上无论是inf还是本身它都不可能是真正的答案,所以这边还是rmq

不过复杂度不影响,少了点常数..

代码

下面注释提供了一些自己拍出来的数据

谁让我不会自动机呢

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional> #define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1 using namespace std; typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
typedef pair<ll,int> PIL; const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 3e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0); int t;
int n,m;
char s[maxn];
int sa[maxn],rk[maxn],height[maxn];
int y[maxn],x[maxn],c[maxn];
void getSa(){
for(int i=1;i<=n;i++)++c[x[i]=s[i]];
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--){ //printf("sa[%d]=%d\n",c[x[i]],i);
sa[c[x[i]]--]=i;
}
for(int k=1;k<=n;k<<=1){
//printf("^^^^%d\n",k);
int num = 0;
for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)++c[x[i]];
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);
x[sa[1]]=1;
num=1;
for(int i = 1; i <= n; i++){
//printf("y[%d]=%d\n",i,y[i]);
}
for(int i=2;i<=n;i++){
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
/*printf("num==%d\n",num);
printf("x[%d]=(y[%d]==y[%d]&&y[%d]==y[%d])?num:++num\n",sa[i],sa[i],sa[i-1],sa[i]+k,sa[i-1]+k);*/
}
if(num==n)break;
m=num;
}
}
void getHeight(){
int k=0;
for(int i=1; i<=n; ++i)rk[sa[i]]=i;
for(int i=1; i<=n; ++i){
if(rk[i]==1) continue;
if(k)--k;
int j=sa[rk[i]-1];
while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])++k;
height[rk[i]]=k;
}
}
set<int>S;
int d[maxn][23];
void init(){
for(int i = 1; i <= n; i++)d[i][0]=height[i];
for(int j = 1; (1<<j)<=n; j++){
for(int i = 1; i+(1<<j)-1<=n; i++){
d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}
}
}
int rmq(int l, int r){
if (l > r) swap (l, r);
int k = 0;
while((1<<(k+1))<=r-l+1)k++;
return min(d[l][k],d[r-(1<<k)+1][k]);
}
int mi[maxn<<2];
void build(int l, int r, int root){
int mid = l+r>>1;
if(l==r){mi[root]=inf;return;}
build(lson);build(rson);
mi[root]=min(mi[lc],mi[rc]);
return;
}
void update(int x, int y, int l, int r, int root){
int mid = l+r>>1;
if(l==r){mi[root]=y;return;}
if(x<=mid)update(x,y,lson);
else update(x,y,rson);
mi[root]=min(mi[lc],mi[rc]);
return;
}
int ask(int x, int y, int l, int r, int root){
int mid=l+r>>1;
if(x<=l&&r<=y)return mi[root];
int ans = inf;
if(x<=mid)ans=min(ans,ask(x,y,lson));
if(y>mid)ans=min(ans,ask(x,y,rson));
return ans;
}
int ntot;
PI Ans[maxn];
int main(){
scanf("%d", &t);
int ncase = 0;
while(t--){
scanf("%s",s+1);
n = strlen(s+1);
m=122;
for(int i = 0; i <= m; i++)c[i]=0;
//for(int i = 0; i <= 2*n+2; i++)x[i]=y[i]=0; getSa();
/*
for(int i = 1; i <= n; i++){
printf(" %d %d %d\n",i,x[i],y[i]);
}*/
getHeight();
printf("Case #%d:\n",++ncase);
S.clear();
init();
build(1,n,1);
for(int i = 1; i <= n; ){
int mxLen = 0;
set<int>::iterator it = S.lower_bound(rk[i]);
if(it!=S.end()){
mxLen=max(mxLen,rmq(rk[i]+1,(*it)));
} if(it!=S.begin()){
it--;
mxLen=max(mxLen,rmq((*it)+1,rk[i]));
}
S.insert(rk[i]);
if(!mxLen){
printf("-1 %d\n",s[i]);
update(rk[i],i,1,n,1);
i++;
continue;
}
int L = -1,R=-1;
int l=1,r=rk[i]-1;
while(l<=r){
int mid=l+r>>1;
if(rmq(mid+1,rk[i])>=mxLen){
L=mid;r=mid-1;
}
else l=mid+1;
}
l=rk[i]+1,r=n;
while(l<=r){
int mid=l+r>>1;
int tmp = rmq(rk[i]+1,mid);
if(rmq(rk[i]+1,mid)>=mxLen){
R=mid;l=mid+1;
}
else r=mid-1;
}
int to = i+mxLen;
if(L==-1)L=inf;
else L=ask(L,rk[i],1,n,1);
if(R==-1)R=inf;
else R=ask(rk[i],R,1,n,1);
int ans=min(L,R);
printf("%d %d\n",mxLen,ans-1); while(i<to){
S.insert(rk[i]);
update(rk[i],i,1,n,1);
i++;
if(i>n)break;
}
}
}
return 0;
}
/* 1
zlikumoyyokhaokil stuiftqhxcksooesore txtvacgqjtvxheeq xnghnjzwjlpiyjlwf qjvxxmhhbhbqingby fsutshglayemjmshy fxoxaepodcfvxaisda 44444
sad
a
d
sa 2
psdkfdsokfpslb
svvvcxxxxaaaa 1
svvvcxxxxaaaa dsfwfqqqfqq
svvvcxxxxaaaa 2
aaaaabbbbbaaabbc
aaaaaa uiuiuiuiiuiui sad
a
d
sa
sdddqqdqqqerr
psdkfdsokfpslbl
svvvcxxxxaaaa
dsfwfqqqfqq dsjdfssdjf
sasasaosos doodfofsdoos
osdosofifi
soodfofofo
asoidosgkoogo
sifioobibninni
sidibvhbjjj
jjajjajjajajaj
siisisiii
iiiiiiii
a
sdiibibi
vv
sddddds */

HDU 5558 Alice's Classified Message(后缀数组+二分+rmq(+线段树?))的更多相关文章

  1. HUID 5558 Alice's Classified Message 后缀数组+单调栈+二分

    http://acm.hdu.edu.cn/showproblem.php?pid=5558 对于每个后缀suffix(i),想要在前面i - 1个suffix中找到一个pos,使得LCP最大.这样做 ...

  2. (HDU 5558) 2015ACM/ICPC亚洲区合肥站---Alice's Classified Message(后缀数组)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5558 Problem Description Alice wants to send a classi ...

  3. POJ 2774 Long Long Message (后缀数组+二分)

    题目大意:求两个字符串的最长公共子串长度 把两个串接在一起,中间放一个#,然后求出height 接下来还是老套路,二分出一个答案ans,然后去验证,如果有连续几个位置的h[i]>=ans,且存在 ...

  4. Luogu3732 [HAOI2017] 供给侧改革 【后缀数组】【线段树】【乱搞】

    题目分析: 这道题我是乱搞的,因为他说$01$串是随机的. 那么我们可以猜测能够让LCP变大的地方很少.求出后缀数组之后可能让LCP变大的地方就等价于从大到小往height里动态加点同时维护这个点左右 ...

  5. Luogu5289 十二省联考2019字符串问题(后缀数组+拓扑排序+线段树/主席树/KDTree)

    先考虑80分做法,即满足A串长度均不小于B串,容易发现每个B串对应的所有A串在后缀数组上都是一段连续区间,线段树优化连边然后判环求最长链即可.场上就写了这个. 100分也没有什么本质区别,没有A串长度 ...

  6. BZOJ 4556: [Tjoi2016&Heoi2016]字符串(后缀数组 + 二分答案 + 主席树 + ST表 or 后缀数组 + 暴力)

    题意 一个长为 \(n\) 的字符串 \(s\),和 \(m\) 个询问.每次询问有 \(4\) 个参数分别为 \(a,b,c,d\). 要你告诉它 \(s[a...b]\) 中的所有子串 和 \(s ...

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

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

  8. HDU 1166 敌兵布阵 (数状数组,或线段树)

    题意:... 析:可以直接用数状数组进行模拟,也可以用线段树. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000&quo ...

  9. BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )

    全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...

随机推荐

  1. Java网络编程系列之TCP连接状态

    1.TCP连接状态 LISTEN:Server端打开一个socket进行监听,状态置为LISTEN SYN_SENT:Client端发送SYN请求给Server端,状态由CLOSED变为SYN_SEN ...

  2. 【转】Hive Data Manipulation Language

    Hive Data Manipulation Language Hive Data Manipulation Language Loading files into tables Syntax Syn ...

  3. Java五子棋小游戏(控制台纯Ai算法)

    Java五子棋小游戏(控制台纯Ai算法) 继续之前的那个五子棋程序 修复了一些已知的小Bug 这里是之前的五子棋程序 原文链接 修复了一些算法缺陷 本次增加了AI算法 可以人机对战 也可以Ai对Ai看 ...

  4. 使用iview遇到问题记录总结

    1.iview设置日期不可用,设置开始开始时间早于结束时间 官网示例,设置今天之前不可选,但是不能识别thisdisabledDate (date) { return date && ...

  5. infer 代码静态分析

    infer 代码静态分析 静态代码分析工具,主要是为了提高我们的代码质量. 通常,我们提高代码质量的方式是通过CodeReview,但是这个过程耗费的人工和时间往往较大.并且随着代码量的增加人肉检测起 ...

  6. Java 用集合实现简单的斗地主发牌

    创建数组.集合,存放数据 public class FightAgainstLandlords { /** * poker集合,存储54张牌 */ private ArrayList<Strin ...

  7. Spring Boot2 系列教程 (五) | yaml 配置文件详解

    自定义属性加载 首先构建 SpringBoot 项目,不会的看这篇旧文 使用 IDEA 构建 Spring Boot 工程. 首先在项目根目录 src >> resource >&g ...

  8. 一个简易的 LED 数字时钟实现方法

    这个应该是已经有很多人做过的东西,我应该只是算手痒,想写一下,所以,花了点时间折腾了这个,顺便把 Dark Mode 的处理也加上了. 首先可以很明确的一点,这个真没技术含量存在,只是需要点耐心. L ...

  9. Go 每日一库之 cobra

    简介 cobra是一个命令行程序库,可以用来编写命令行程序.同时,它也提供了一个脚手架, 用于生成基于 cobra 的应用程序框架.非常多知名的开源项目使用了 cobra 库构建命令行,如Kubern ...

  10. docker-主从服务部署

    欢迎访问我的博客http://www.liyblog.top 我的博客里会有更详细的信息,而且留言必回,手把手给你解释不懂的地方   1.mysql部署   mysql镜像拉取 docker pull ...