BZOJ_4698_Sdoi2008 Sandy的卡片_后缀数组

Description

Sandy和Sue的热衷于收集干脆面中的卡片。然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积
攒卡片兑换超炫的人物模型。每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型
,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人
物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。Sandy的卡片数远
远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片
,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到
哪个等级的人物模型。

Input

第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数
第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中
的第j个数
n<=1000,M<=1000,2<=Mi<=101

Output

一个数k,表示可以获得的最高等级。

Sample Input

2
2 1 2
3 4 5 9

Sample Output

2

根据定义,差分数组相同的两个子串就是相同的。
那不妨把长度为l的一个字符串变成一个长度为l-1的差分字符串。
这步需要一些处理,因为差分后可能出现负数之类的。
然后问题转化为求多个串的最长公共子串。
这里使用后缀数组来求这个。
我们把所有串拼起来,中间插入一个极大值后求这个大串的后缀数组,同时维护出每个字符是在哪个后缀中。
之后要在sa上选择一个尽可能短的区间,使得所有字符串都在这里至少出现一次。
这个用一下双指针,然后对应的答案就是j+1~i这部分height的最小值。
用单调队列求(强行比ST表优越)
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1000050
int r[N],sa[N],wa[N],wb[N],wv[N],Rank[N],height[N],n,ws[N],cnt,idx[N],H[1050],tot,ans,Q[N],m;
int w[100050];
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd() {
int x=0; char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
void build_sa_array() {
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[x[i]=r[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;
for(p=j=1;p<n;j<<=1,m=p) {
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]-j>=0) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) ws[i]=0;
for(i=0;i<n;i++) ws[wv[i]]++;
for(i=1;i<m;i++) ws[i]+=ws[i-1];
for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];
for(t=x,x=y,y=t,i=p=1,x[sa[0]]=0;i<n;i++) {
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j]) x[sa[i]]=p-1;
else x[sa[i]]=p++;
}
}
for(i=1;i<n;i++) Rank[sa[i]]=i;
for(i=p=0;i<n-1;height[Rank[i++]]=p)
for(p?p--:0,j=sa[Rank[i]-1];r[i+p]==r[j+p];p++);
}
int main() {
int i,j=0;
cnt=rd();
int minn=1<<30,maxx=0;
for(j=1;j<=cnt;j++) {
int lim;
lim=rd();
for(i=0;i<lim;i++) w[i]=rd();
for(i=1;i<lim;i++) idx[n]=j,r[n++]=w[i]-w[i-1],minn=min(minn,r[n-1]),maxx=max(maxx,r[n-1]);
n++;
}
m=maxx-minn+1;
for(i=0;i<n;i++) {
if(idx[i]) r[i]-=minn-1;
else r[i]=m+1;
}
r[n++]=0; m+=2;
build_sa_array();
int ll=0,rr=0; j=0;
for(i=0;i<n;i++) {
H[idx[sa[i]]]++; if(H[idx[sa[i]]]==1&&idx[sa[i]]) tot++;
while(ll<rr&&height[Q[rr-1]]>height[i]) rr--;
Q[rr++]=i;
if(tot!=cnt) continue;
while(j<i&&tot==cnt) {
H[idx[sa[j]]]--;
if(H[idx[sa[j]]]==0&&idx[sa[j]]) tot--;
j++;
}
j--; H[idx[sa[j]]]++;
if(H[idx[sa[j]]]==1&&idx[sa[j]]) tot++;
while(ll<rr&&Q[ll]<=j) ll++;
if(tot==cnt) {
ans=max(ans,height[Q[ll]]);
}
}
printf("%d\n",ans+1);
}

最新文章

  1. web应用程序
  2. 执行shell脚本,报错坏的解释器
  3. java IO流复制图片
  4. 7月17日——高校就业信息网站功能及数据获取之python爬虫
  5. Port Hacking
  6. TJI读书笔记12-接口
  7. SmartDo数据挖掘思路
  8. HTML5每日一练之progress标签的应用
  9. bzoj2791
  10. 在Linux下查看环境变量
  11. python之路,Day24 常用设计模式学习
  12. Hibernate 、多表关联映射-多对一关系(many-to-one)
  13. Android-用你自己的自定义图像资源(2)
  14. hdu 1498
  15. JDK1.7源码分析01-Collection
  16. 阿里云ECS云服务器的简单使用
  17. 2059 - Authentication plugin &#39;caching_sha2_password&#39; cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found
  18. SpringCache学习实践
  19. 读懂掌握 Python logging 模块源码 (附带一些 example)
  20. 涂抹mysql笔记-数据备份和恢复

热门文章

  1. CentOS 7.5 初始网络配置
  2. codevs——1570 去看电影
  3. python和python-dev
  4. 存code
  5. qq空间微博等更多社交平台分享
  6. 2.JAVA语言基础部分
  7. weex stream 方法封装
  8. FLEX接收外部参数 .
  9. 【Mongodb教程 第十九课 】PHP与MONGODB的条件查询
  10. 【转载】读懂IL代码就这么简单(二)