https://www.lydsy.com/JudgeOnline/problem.php?id=4698

题意:求N个字符串中最长的相同字串的长度,相同的定义是:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。

这题的难点在于相同的定义,在这样的定义下一般的字符串匹配算法就不适用了。

但是可以通过一个操作,将前后相邻的字符串差分形成一个长度为len - 1的差分串,原来的相同下的定义就转为了差分串的完全相同,证明显然。

在这种情况下,再把字符串全部拼接起来,用特殊字符隔开,然后二分他们的长度去做后缀数组,看有没有相邻的一个区间同时满足长度最大并且包含所有K个字符串。

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = ,f = ;char c = getchar();while (c<'' || c>''){if (c == '-') f = -;c = getchar();}
while (c >= ''&&c <= ''){x = x * + c - '';c = getchar();}return x*f;}
const double eps = 1e-;
const int maxn = 1e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
int N,M,K;
int str[maxn],id[maxn];
int a[maxn],Height[maxn];
int tax[maxn],tp[maxn],sa[maxn],rak[maxn];
void Qsort(){
for(int i = ; i <= M; i ++) tax[i] = ;
for(int i = ; i <= N ; i ++) tax[rak[i]]++;
for(int i = ; i <= M ; i ++) tax[i] += tax[i - ];
for(int i = N; i >= ; i --) sa[tax[rak[tp[i]]]--] = tp[i];
}
void SA(){
for(int i = ; i <= N; i ++) rak[i] = str[i],tp[i] = i;
Qsort();
for(int w = ,p = ; p < N;w <<= , M = p){
p = ;
for(int i = ; i <= w; i ++) tp[++p] = N - w + i;
for(int i = ; i <= N ; i ++) if(sa[i] > w) tp[++p] = sa[i] - w;
Qsort(); swap(tp,rak);
rak[sa[]] = p = ;
for(int i = ; i <= N ; i ++){
rak[sa[i]] = (tp[sa[i]] == tp[sa[i - ]] && tp[sa[i] + w] == tp[sa[i - ] + w])?p:++p;
}
}
}
void Get_Height(){
int k = ,j;
for(int i = ; i <= N; i ++){
if(k) k --;
int j = sa[rak[i] - ];
while(str[j + k] == str[i + k]) k++;
Height[rak[i]] = k;
}
}
int Stack[maxn];
bool vis[maxn];
bool check(int x){
int top = ;
int num = K;
for(int i = ; i <= K; i ++) vis[i] = ;
for(int i = ; i <= N ; i ++){
if(Height[i] >= x){
if(!vis[id[sa[i]]]){
vis[id[sa[i]]] = ;
Stack[++top] = id[sa[i]];
num--;
}
if(!vis[id[sa[i - ]]]){
vis[id[sa[i - ]]] = ;
Stack[++top] = id[sa[i - ]];
num--;
}
if(!num) return true;
}else{
for(int j = ; j <= top; j ++) vis[Stack[j]] = ;
top = ;
num = K;
}
}
return false;
}
int solve(){
int l = ,r = N - ;
int ans = ;
while(l <= r){
int m = l + r >> ;
if(check(m)){
ans = m;
l = m + ;
}else{
r = m - ;
}
}
return ans + ;
}
int main(){
Sca(K); N = ;
M = ;
int MIN = INF;
for(int i = ; i <= K ; i ++){
int x = read();
a[] = read();
for(int j = ; j <= x; j ++){
a[j] = read();
str[++N] = a[j] - a[j - ];
MIN = min(MIN,a[j] - a[j - ]);
id[N] = i;
}
str[++N] = ++M; id[N] = i;
}
if(MIN <= ){
MIN = -MIN + ;
for(int i = ; i <= N ; i ++) str[i] += MIN;
M += MIN;
}
SA(); Get_Height();
Pri(solve());
return ;
}

BZOJ4698 差分 + 二分 + SA的更多相关文章

  1. P1083 借教室(差分+二分)

    P1083 借教室 第一眼:线段树. 然鹅懒得写. 正解:差分+二分. 显然订单合法的上线可以二分 然后差分数组维护一下.没了. #include<iostream> #include&l ...

  2. [NOIP2015]运输计划 线段树or差分二分

    目录 [NOIP2015]运输计划 链接 思路1 暴力数据结构 思路2 二分树上差分 总的 代码1 代码2 [NOIP2015]运输计划 链接 luogu 好久没写博客了,水一篇波. 思路1 暴力数据 ...

  3. ZZNU-OJ-2098 : Drink coffee【线段树合并区间或者 差分 + 二分索引树】

    : Drink coffee 时间限制: Sec 内存限制: MiB 提交: 答案正确: 提交 状态 讨论区 题目描述 为了在上课时保持清醒,凯伦需要一些咖啡.咖啡爱好者凯伦想知道最佳的温度来冲煮完美 ...

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

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

  5. poj 1743 Musical Theme【二分+SA】

    差分,然后二分长度mid,判断是把height按照min不小于mid分组,取最大最小的sa位置看是否>=mid即可,注意差分后最后答案要+1 #include<iostream> # ...

  6. BZOJ 4698: Sdoi2008 Sandy的卡片(后缀数组+差分+二分答案)

    传送门 解题思路 看到一个子串加一个数字到另一个子串,自然可以想到差分.然后要把所有串都拼起来,求出\(height\)数组后可以二分答案来做,每次二分一个答案后统计一下连续的\(height> ...

  7. NOIP2012借教室[线段树|离线 差分 二分答案]

    题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要 向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借教室的信息,我们自 ...

  8. 【BZOJ-4326】运输计划 树链剖分 + 树上差分 + 二分

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 703  Solved: 461[Submit][Status] ...

  9. [NOIP 2015]运输计划-[树上差分+二分答案]-解题报告

    [NOIP 2015]运输计划 题面: A[NOIP2015 Day2]运输计划 时间限制 : 20000 MS 空间限制 : 262144 KB 问题描述 公元 2044 年,人类进入了宇宙纪元. ...

随机推荐

  1. 做接口自动化时候,一些登录头信息可以通过aop的方式进行增强

    做接口自动化时候,一些登录头信息可以通过aop的方式进行增强

  2. 搭建Hexo博客(三)—换电脑继续写Hexo博客

    Hexo和GitHub搭建博客的原理是:Hexo将source下的md文件生成静态的html页面,存放到public目录中,这一步是由命令:hexo -g完成.接下来执行hexo -d命令,就将pub ...

  3. 【数学建模】day01-线性规划问题

      线性规划问题是在一组线性约束条件下,求线性目标函数最大/最小值的问题.这些约束条件有不等式约束.等式约束以及边界约束,这和中学讲的线性规划无异. 此类问题的MATLAB标准形式为: 其中,max问 ...

  4. Row_Number() over()

    分页 ROW_NUMBER() OVER (order by ID) 是先把ID列排序,再为排序以后的每条ID记录返回一个序号.

  5. linux系统命令大全

    文件管理 cat chattr chgrp chmod chown cksum cmp cp cut diff diffstat file find git gitview in indent les ...

  6. 清北澡堂 Day2 上午 一些比较重要的关于数论的知识整理

    1.算数基本定理: 对于任意的大于1的正整数N,N一定能够分解成有限个质数的乘积,即 其中P1<P2<...<Pk,a1,a2,...,ak>=1; 证: 存在性: 若存在最小 ...

  7. King of Destruction HDU - 3002 && HDU - 3691(全局最小割)

    求无向图的最小割 有没有源点都一样,不影响 #include <iostream> #include <cstdio> #include <sstream> #in ...

  8. npm config 删除变量

    问题 安装npm时,使用npm config set 命令重新设置了变量,但是设置变量时少了个空格,设置错了.使用npm config ls -l 查看环境变量 添加错的这一个,应该如何删除? 解决 ...

  9. MT【277】华中科技大学理科实验班选拔之三次方程

    (2015华中科技大学理科实验班选拔)已知三次方程$x^3+ax^2+bx+x=0$有三个实数根.(1)若三个实根为$x_1,x_2,x_3$,且$x_1\le x_2\le x_3,a,b$为常数, ...

  10. 解决win10“cmd自动弹出一闪而过”问题的方法

    1.禁用CMD win+Q gpedit 打开组策略 用户配置--管理模板--系统--阻止访问命令提示符--已启用. 2.启用PowerShell PS:需要使用CMD时可用powershell代替: ...