写一种\(O(nm)\)的做法,也就是\(O(\sum 串长)\)的。

先通过差分转化,把每个数变成这个数与上一个数的差,第一个数去掉,答案就是最长公共子串+1

按照套路把所有串拼起来,中间加一个分隔符号,然后用DC3求出SA以及height

(DC3我也不会,蒯的TJJ的板子,因为一般用倍增SA足够了)

对每个后缀可以知道它在原来的第几个串,那么求出SA以后,答案就是一段区间\([l,r]\),即排名为\([l,r]\)的这些后缀,而且必须覆盖原来的所有串,长度就是这些后缀的LCP,就是一段height的最小值

枚举左端点,那么最小的右端点一定不小于上一个的最小右端点,所以直接维护右端点以及这一段区间包括原来每一个串的数量就好了

最小值可以直接单调队列维护

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
typedef unsigned long long ulint;
namespace input
{
const int bufl = 1<<14;
char buf[bufl],*s=buf,*t=buf;
inline int fetch()
{
if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
return *s++;
}
inline int gi()
{
register int a=0,b=1,c=fetch();
while(!isdigit(c))b^=c=='-',c=fetch();
while(isdigit(c))a=a*10+c-48,c=fetch();
return b?a:-a;
}
}
using input::gi;
const int N = 202007 , N3 = N*3 , maxalpha = 99999;
int wa[N3],wb[N3],wv[N3],buc[N3];
inline void bsort(int *s,int *a,int *b,int n,int m)
{
register int i;
for(i=0;i<n;i++)wv[i]=s[a[i]];
for(i=0;i<m;i++)buc[i]=0;
for(i=0;i<n;i++)buc[wv[i]]++;
for(i=1;i<m;i++)buc[i]+=buc[i-1];
for(i=n-1;i>=0;i--)b[--buc[wv[i]]]=a[i];
}
inline int c0(int *s,int a,int b)
{
return s[a]==s[b] && s[a+1]==s[b+1] && s[a+2]==s[b+2];
}
inline int c12(int k,int *s,int a,int b)
{
if(k==2)return s[a]<s[b] || (s[a]==s[b] && c12(k-1,s,a+1,b+1));
return s[a]<s[b] || (s[a]==s[b] && wv[a+1]<wv[b+1]);
}
#define f(x) ((x)/3+((x)%3==1?0:tb))
#define g(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
void dc3(int *s,int *sa,int n,int m)
{
int i,j,*sn=s+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
s[n]=s[n+1]=0;
for(i=0;i<n;i++)if(i%3!=0)wa[tbc++]=i;
bsort(s+2,wa,wb,tbc,m),bsort(s+1,wb,wa,tbc,m),bsort(s,wa,wb,tbc,m);
for(sn[f(wb[0])]=0,p=1,i=1;i<tbc;i++)sn[f(wb[i])]=c0(s,wb[i-1],wb[i])?p-1:p++;
if(p<tbc)dc3(sn,san,tbc,p);
else for(i=0;i<tbc;i++)san[sn[i]]=i;
for(i=0;i<tbc;i++)if(san[i]<tb)wb[ta++]=san[i]*3;
if(n%3==1)wb[ta++]=n-1;
bsort(s,wb,wa,ta,m);
for(i=0;i<tbc;i++)wv[wb[i]=g(san[i])]=i;
for(i=j=p=0;i<ta && j<tbc;p++)sa[p]=c12(wb[j]%3,s,wa[i],wb[j])?wa[i++]:wb[j++];
for(;i<ta;p++)sa[p]=wa[i++];
for(;j<tbc;p++)sa[p]=wb[j++];
}
#undef f
#undef g
void calheight(int *s,int *sa,int n,int *rk,int *ht)
{
register int i,j,k=0;
for(i=1;i<=n;++i)rk[sa[i]]=i;
for(i=0;i<n;ht[rk[i++]]=k)for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k] && k<n;++k);
return;
}
char s[N3];
int n,ss[N3],sa[N3],rk[N3],ht[N3];
int p[N3],S[N3];
int que[N3],hd,tl,cnt[N3];
int main()
{
int NN=gi(),n=0,sep=0;
if(NN==1)return printf("%d\n",gi()),0;
while(NN--){
int t=gi(),lst=gi();
while(--t){
int x=gi();
S[n++]=lst-x+10000;
lst=x;
}
S[n++]=++sep;
}
s[n]=0;
dc3(S,sa,n+1,20000);
calheight(S,sa,n,rk,ht);
int k=1;
for(int i=0;i<n;++i)if(S[i]>1000)p[i]=k;else ++k;//p[i]是后缀i属于原来的第几个串
int CNT=0,r=k,Mx=0;//cnt是原来每个串的出现次数,CNT是总的
hd=tl=0;
--k;
for(int i=k+1;i<=n;++i){
while(r<=n&&CNT<k){
if(cnt[p[sa[r]]]++==0)++CNT;
if(r){
while((hd^tl)&&ht[que[tl-1]]>ht[r])--tl;
que[tl++]=r;
}
++r;
}
if(CNT<k)break;
while((hd^tl)&&que[hd]<=i)++hd;
if(hd^tl)Mx=std::max(Mx,ht[que[hd]]);
if(--cnt[p[sa[i]]]==0)--CNT;
}
printf("%d\n",Mx+1);
return 0;
}

(大括号换行的是蒯的板子,不换行的也就是核心代码是我自己写的,DC3只是为了保证复杂度而已)

P2463 [SDOI2008]Sandy的卡片的更多相关文章

  1. 洛谷 P2463 [SDOI2008]Sandy的卡片 解题报告

    P2463 [SDOI2008]Sandy的卡片 题意 给\(n(\le 1000)\)串,定义两个串相等为"长度相同,且一个串每个数加某个数与另一个串完全相同",求所有串的最长公 ...

  2. bzoj4698 / P2463 [SDOI2008]Sandy的卡片

    P2463 [SDOI2008]Sandy的卡片 直接二分长度暴力匹配....... 跑的还挺快 (正解是后缀数组的样子) #include<iostream> #include<c ...

  3. P2463 [SDOI2008]Sandy的卡片[差分+串拼接后缀数组]

    P2463 [SDOI2008]Sandy的卡片 套路都差不多,都是差分后二分答案找lcp.只是这题要把多个串拼接起来成为一个大串,中间用某些值域中没有的数字相隔(最好间隔符都不一样想想为什么),排序 ...

  4. 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)

    题目链接:https://www.luogu.org/problem/P2463 [题意] 求出N个串中都出现的相同子串的最长长度,相同子串的定义如题:所有元素加上一个数变成另一个,则这两个串相同,可 ...

  5. Luogu P2463 [SDOI2008]Sandy的卡片

    题目链接 \(Click\) \(Here\) 真的好麻烦啊..事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦..(最好是八分钟能无脑把\(SA\)码对的程度\(QAQ\) ...

  6. 洛咕 P2463 [SDOI2008]Sandy的卡片

    哈希水过. 首先这是一段delta相同的序列,按照套路差分一下,b[i]=a[i]-a[i-1],然后就是这些序列的最长公共子段 由于数据范围很小,就可以二分,枚举第一个序列的子段然后每个子序列暴力c ...

  7. [洛谷P2463][SDOI2008]Sandy的卡片

    题目大意:有$n$个字符串,求这$n$个字符串中最长的相似公共字串,相似的定义是加上一个数后相同 题解:差分,建广义后缀自动机,然后求出每个点在多少个字符串中出现过,若在$n$个中都出现,就更新答案 ...

  8. BZOJ 4698: Sdoi2008 Sandy的卡片

    4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 106  Solved: 40[Submit][Stat ...

  9. BZOJ 4698: Sdoi2008 Sandy的卡片 [后缀自动机]

    4698: Sdoi2008 Sandy的卡片 题意:差分后就是多个串LCS SAM+map大法好 模板打错 智力-2 #include <iostream> #include <c ...

随机推荐

  1. Python+Selenium笔记(二):配置谷歌+IE环境

    #有的时候可能要访问外国的网站下载资料或工具,这时可能出现各种问题,例如谷歌人机验证显示不了.网站打不开等,建议使用一个FQ软件 (一)  设置IE (1)   http://docs.seleniu ...

  2. Oracle EBS INV 创建物料搬运单行

    CREATE OR REPLACE PROCEDURE CreateMoveOrderLines AS -- Common Declarations l_api_version NUMBER := 1 ...

  3. 总结获取原生JS(javascript)的父节点、子节点、兄弟节点

    关于原生JS获取节点,一直是个头疼的问题,而且调用方法的名字又贼长了,所以我选择用JQ,好像跑题了-- 话不多说看代码 获取父节点 及 父节点下所有子节点(兄弟节点) <ul> <l ...

  4. 【转】Redis学习---NoSQL和SQL的区别及使用场景

    什么是NoSQL NoSQL,指的是非关系型的数据库.NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称,它具有非关系型.分布式.不提供ACID的数 ...

  5. iOS 固定定位不兼容、input获取焦点后位置不对。

    第一次写博客~  大家悠着看,有则改之,无则加冕,对不对的给个回复,让我知道你的存在. 在做活动页的时候,经常会碰到一些需要弹出显示的输入框(情节前提:本人安卓机~),前天自己写的时候自己调试没问题后 ...

  6. Office Web app server 2013 目前无法和windows server 2012 R2兼容。

    另外旧版的office文档和PDF格式不支持预览功能.

  7. 关于Vue的nextTick的一点小理解

    官方文档表示:为了在数据变化之后等待Vue完成更新DOM,可以在数据变化之后立即执行Vue.$nextTick(callback),这样回调函数就可以在数据变化之后立即执行. 这段话的意思是: 例如: ...

  8. C#实现的协同过滤算法

    using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace SlopeOn ...

  9. BZOJ4236:JOIOJI(乱搞)

    Description JOIOJI桑是JOI君的叔叔.“JOIOJI”这个名字是由“J.O.I”三个字母各两个构成的. 最近,JOIOJI桑有了一个孩子.JOIOJI桑想让自己孩子的名字和自己一样由 ...

  10. ES6简介之let和const命令解说

    一.var申明变量 学习过JavaScript的同学都应该知道,ES5中申明变量使用var,ES5中的var可以说是无所不能的,所有类型的变量都是由var来申明,但往往很多使用者不知道var申明的变量 ...