【BZOJ4698】[SDOI2008] Sandy的卡片(后缀数组+二分)
大致题意: 给你\(N\)个序列,若定义两个相同子串为一个子串内所有数加上一个数后能变成另一个串,求所有序列中的最长相同子串的长度。
简单的转化
首先,我们对题目进行一个简单的转化。
要求子串内所有数加上一个数后能变成另一个串,实际上就是要求这两个子串中相邻元素之差相等。
因此,我们只要将相邻两元素之差存储下来,就变成求最长公共子串的长度了。
后缀数组
要做这道题,我们需要使用后缀数组。
不过此题不需要求\(LCP\),只要将所有序列拼在一起,中间用一个互不相同的字符隔开,再求出\(Height\)数组,然后二分即可。
如何二分
我们可以二分答案\(len\)。
考虑如何验证是否存在一个长度大于等于\(len\)的公共子串。
其实这个问题等价于:是否存在若干连续的后缀,满足它们的\(LCP\ge len\),且它们在\(n\)个序列中皆有分布。
而这其实在求出\(SA\)数组和\(Height\)数组之后直接\(O(n)\)扫一遍就可以了。
乘上二分\(O(logn)\)的时间复杂度,总复杂度是\(O(nlogn)\)的。
注意最后答案要加\(1\)。
代码
#include<bits/stdc++.h>
#define N 1000
#define Len 1500000
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,m,len,s[Len+5],p[Len+5];
class Class_FIO
{
private:
#define Fsize 100000
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
#define pc(ch) (void)(putchar(ch))
int Top,FoutSIze;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
public:
Class_FIO() {A=B=Fin;}
inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
inline void write(int x) {if(!x) return pc('0');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
}F;
class Class_SuffixArray//后缀数组
{
private:
int n,Top,vis[N+5],Stack[N+5],SA[Len+5],Height[Len+5],rk[Len+5],pos[Len+5],tot[Len+5];
inline void RadixSort(int S)
{
register int i;
for(i=0;i<=S;++i) tot[i]=0;
for(i=1;i<=n;++i) ++tot[rk[i]];
for(i=1;i<=S;++i) tot[i]+=tot[i-1];
for(i=n;i;--i) SA[tot[rk[pos[i]]]--]=pos[i];
}
inline void GetSA(int *s)
{
register int i,k,cnt=0,Size=N<<1;
for(i=1;i<=n;++i) rk[pos[i]=i]=s[i];
for(RadixSort(Size),k=1;cnt<n;k<<=1)
{
for(Size=cnt,cnt=0,i=1;i<=k;++i) pos[++cnt]=n-k+i;
for(i=1;i<=n;++i) SA[i]>k&&(pos[++cnt]=SA[i]-k);
for(RadixSort(Size),i=1;i<=n;++i) pos[i]=rk[i];
for(rk[SA[1]]=cnt=1,i=2;i<=n;++i) rk[SA[i]]=(pos[SA[i-1]]^pos[SA[i]]||pos[SA[i-1]+k]^pos[SA[i]+k])?++cnt:cnt;
}
}
inline void GetHeight(int *s)
{
register int i,j,k=0;
for(i=1;i<=n;++i) rk[SA[i]]=i;
for(i=1;i<=n;++i)
{
if(!(rk[i]^1)) continue;
k&&--k,j=SA[rk[i]-1];
while(i+k<=n&&j+k<=n&&!(s[i+k]^s[j+k])) ++k;
Height[rk[i]]=k;
}
}
public:
inline void Init(int len,int *s) {n=len,GetSA(s),GetHeight(s);}
inline bool Check(int t,int x)//O(n)验证
{
register int i;
while(Top) vis[Stack[Top--]]=0;//清空
for(i=1;i<=n;++i)
{
if(Height[i]<x) while(Top) vis[Stack[Top--]]=0;//如果Height[i]<x,即LCP(i,i-1)<x,则说明不可行,清空
if(!vis[p[SA[i]]]&&(vis[Stack[++Top]=p[SA[i]]]=1)&&!(Top^t)) return true;//如果在n个字符串中皆有分布,就返回true
}
return false;//如果找不到,返回false
}
}S;
int main()
{
register int i,j,x,y,z,cnt=0,l,r,mid;
for(F.read(n),i=1;i<=n;++i,s[++len]=N+cnt) for(F.read(x),F.read(y),++cnt,j=1;j<x;++j) F.read(z),s[++len]=z-y,y=z,p[len]=cnt;//读入并存下相邻元素的差值
for(S.Init(len,s),mid=(l=0)+(r=len)+1>>1;l<r;mid=l+r+1>>1) S.Check(n,mid)?l=mid:r=mid-1;//二分答案
return F.write(l+1),0;
}
【BZOJ4698】[SDOI2008] Sandy的卡片(后缀数组+二分)的更多相关文章
- BZOJ4698: Sdoi2008 Sandy的卡片(后缀数组 二分)
题意 题目链接 Sol 不要问我为什么发两篇blog,就是为了骗访问量 后缀数组的也比较好想,先把所有位置差分,然后在height数组中二分就行了 数据好水啊 // luogu-judger-enab ...
- 【BZOJ4698】Sdoi2008 Sandy的卡片 后缀数组+RMQ
[BZOJ4698]Sdoi2008 Sandy的卡片 Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡 ...
- 【BZOJ-4698】Sandy的卡片 后缀数组
4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 140 Solved: 55[Submit][Stat ...
- 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列 ...
- BZOJ 4698: Sdoi2008 Sandy的卡片 后缀数组 + RMQ + 查分
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...
- SDOI2008 Sandy的卡片( 后缀数组 )
求出后缀数组, 然后二分答案, 对height数组分组检验答案. 时间复杂度O(|S| log|S|) ------------------------------------------------ ...
- BZOJ 4698: Sdoi2008 Sandy的卡片(后缀数组+差分+二分答案)
传送门 解题思路 看到一个子串加一个数字到另一个子串,自然可以想到差分.然后要把所有串都拼起来,求出\(height\)数组后可以二分答案来做,每次二分一个答案后统计一下连续的\(height> ...
- 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)
题目链接:https://www.luogu.org/problem/P2463 [题意] 求出N个串中都出现的相同子串的最长长度,相同子串的定义如题:所有元素加上一个数变成另一个,则这两个串相同,可 ...
- [BZOJ4698][SDOI2008]Sandy的卡片(后缀自动机)
差分之后就是求多串LCS. 对其中一个串建SAM,然后把其它串放在上面跑. 对SAM上的每个状态都用f[x]记录这个状态与当前串的最长匹配长度,res[x]是对每次的f[x]取最小值.答案就是res[ ...
- BZOJ 4698: Sdoi2008 Sandy的卡片 [后缀自动机]
4698: Sdoi2008 Sandy的卡片 题意:差分后就是多个串LCS SAM+map大法好 模板打错 智力-2 #include <iostream> #include <c ...
随机推荐
- sqoop 安装与命令
1. 下载: wget http://mirrors.shu.edu.cn/apache/sqoop/1.4.7/sqoop-1.4.7.bin__hadoop-2.6.0.tar.gz 2. 解 ...
- 【转】Asp.Net页面生命周期
源地址:http://www.cnblogs.com/xhwy/archive/2012/05/20/2510178.html
- jmeter - 函数:Random 随机函数的使用
场景:在做接口测试时,比如说要求用户的手机号码不允许重复,那此时可以通过Random 随机函数来解决此问题: 1.在JMeter 工具中,选择{选项-函数助手对话框-} 函数助手中选择 Random ...
- OJDBC版本区别:ojdbc14.jar,ojdbc5.jar和ojdbc6.jar的区别
classes12.jar - for Java 1.2 and 1.3ojdbc14.jar - for Java 1.4 and 1.5ojdbc5.jar - for Java 1.5ojdbc ...
- Java基础笔记(十五)——封装(续)static关键字
static 静态的,用static修饰的成员叫静态成员或类成员.类实例化的所有对象都会共用同一块静态空间.一个对象将值改变,其它对象的值也就随之改变了. 如:public static int pr ...
- webpack坑系列--安装webpack-cli
综下所述: 还是装3.11.0版本吧 cnpm i webpack@3.11.0 -D 最近在学习webpack过程中,根据官方文档推荐局部安装webpack,执行webpack -h命令出现以下提示 ...
- Luogu P5103 「JOI 2016 Final」断层 树状数组or线段树+脑子
太神仙了这题... 原来的地面上升,可以倒着操作(时光倒流),转化为地面沉降,最后的答案就是每个点的深度. 下面的1,2操作均定义为向下沉降(与原题意的变换相反): 首先这个题目只会操作前缀和后缀,并 ...
- Base64Utils
package com.yundaex.common.crypto.base64; import java.io.ByteArrayInputStream; import java.io.ByteAr ...
- Navicat for mysql远程连接数据库详解(1130错误解决方法)
用Navicat for mysql连接数据库测试下连接 如果出现1130错误 错误代码是1130,ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to ...
- 敏捷开发(Agile development)
敏捷开发(Agile development) 敏捷开发是一种以人为核心.迭代.循序渐进的开发方法.在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征. ...