【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 ...
随机推荐
- 2018杭电多校第五场1002(暴力DFS【数位】,剪枝)
//never use translation#include<bits/stdc++.h>using namespace std;int k;char a[20];//储存每个数的数值i ...
- “Enterprise Architect”和数据库的不解之缘
前言 在这个大数据盛行的时代,和数据打交道变的必不可少了,所有如果有工具来规范我们的数据库会更加方便我们的生活.这次机房,我们利用EA(Enterprise Architect)自动生成SQL语句来达 ...
- 清除input框对浏览器保存的用户名和密码自动填充问题
清除input框对浏览器保存的用户名和密码自动填充问题: type类型写如下写法,聚焦的时候type类型为“password” <input ng-model="getpwd" ...
- 设计模式实战研磨 ——第1篇 UML环境搭建
starUML是开源的基于统一模式语言与模式驱动开发的平台,前身是Plastic,从1996年开始开发.1998年开始,Plastic转变为UML建模工具.2005年改名为StarUML,最新版本St ...
- Python中list作为默认参数的陷阱
在Python中,作为默认参数的一定要是不可变对象,如果是可变对象,就会出现问题,稍不注意,就会调入陷阱,尤其是初学者,比如我(┬_┬). 我们来看一个例子. def add(L=[]): L.app ...
- jmeter小问题解决方案合集
问题1.在http请求,post的body中输入中文,显示乱码,怎么解决? 在jmeter的bin目录下,找到这个文件jmeter.properties,把jsyntaxtextarea.font.f ...
- 点击对应的a标签返回相应的第几个
面试中遇到的问题,前两天一直没有解决,今天想想还是得要想办法才行,其实仔细想的话很简单,惭愧啊,面试的时候没有做出来! 题目是这样的,如果一个body中有5个a标签,当我们点击对应的a标签时,aler ...
- Ubuntu16.04安装Nvidia显卡驱动+Cuda8.0+Cudnn6.0
一.安装Nvidia显卡驱动(gtx1050ti) 参考链接:Ubuntu16.04.2 LTS 64bit系统装机记录中的显卡驱动安装部分. 二.安装Cuda8.0 1.确定自己的系统信息,以Ubu ...
- linux命令ln
创建软连接 ln -s 源文件 目标文件(指向源文件) ln -s /home/test/ /wang
- 自定义ClassLoader加载class文件
package com.yd.wmsc.util; public class Test { public void say(){ System.out.println("Say Hello& ...