【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 ...
随机推荐
- Eclipse项目中乱码问题的解决办法
一.产生的原因: 1.Http协议进行通信的时候是基于请求和响应的,传输的内容我们称之为报文! 2.Http协议会按照一定的规则将报文编码,然后在读取的时候再使用响应的解码格式进行解码! 3.这个一定 ...
- Spring动态切换数据源
11 //定义数据源枚举public enum DataSourceKey { master, slave, } 22 /** * 数据源路由 */ @Slf4j public class Dynam ...
- 把查询出来的结果进行修改再赋值给list
List<RivBillNoPatternL> list = this.jdbcTemplate.getJdbcOperations().query(sqlSb.toString(), p ...
- scrapy可视化管理工具spiderkeeper使用笔记
http://www.scrapyd.cn/doc/156.html 入门中文教程 spiderkeeper是一款开源的spider管理工具,可以方便的进行爬虫的启动,暂停,定时,同时可以查看分布式 ...
- mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译
mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...
- JavaScript跨域资源请求(CORS)解决方案
跨域:当协议.主域名.子域名.端口号中任意一个不相同时都不算同一个域,而在不同域之间请求数据即为跨域请求.解决方法有以下几种(如有错误欢迎指出)以请求图片url为例: 1.通过XMLHttpReque ...
- LeetCode 128 Longest Consecutive Sequence 一个无序整数数组中找到最长连续序列
Given an unsorted array of integers, find the length of the longest consecutive elements sequence.Fo ...
- Java面向对象_内部类
概念:内部类就是类的内部定义的类 成员内部类格式如下:class Outer{ class Inner{} } 编译上述代码会产生两个文件:Outer.class和Outer$Inner.class ...
- 常见的SQL错误和解决方法
前言 今天你会看到每个人——从新手到专家——在使用SQL时犯的各种常见错误.你不能永远避免犯任何错误,但是熟悉广泛的错误将帮助你在尽可能短的时间内解决这些错误. 注:在我们的例子中我们使用的是Orac ...
- .NET导出excel方法
//导出 private string outFileName = ""; private string fullFilename = ""; private ...