题目描述

Sandy和Sue的热衷于收集干脆面中的卡片。

然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型。

每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型。相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串。

Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡片送给Sandy,在Sue的帮助下,Sandy终于集够了N张卡片,但是,Sandy并不清楚他可以兑换到哪个等级的人物模型,现在,请你帮助Sandy和Sue,看看他们最高能够得到哪个等级的人物模型。

输入输出格式

输入格式:

第一行为一个数N,表示可以兑换人物模型最少需要的卡片数,即Sandy现在有的卡片数

第i+1行到第i+N行每行第一个数为第i张卡片序列的长度Mi,之后j+1到j+1+Mi个数,用空格分隔,分别表示序列中的第j个数

输出格式:

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

输入输出样例

输入样例#1: 复制

2
2 1 2
3 4 5 9
输出样例#1: 复制

2

说明

数据范围:

30%的数据保证n<=50

100%的数据保证n<=1000,M<=1000,2<=Mi<=101

题意:

给定几串序列,问他们最长公共子序列是多长。

思路:

类似之前做的Muisical, Themehttps://www.cnblogs.com/wyboooo/p/9865919.html

都是可以通过增加一个定值,所以只需要处理间隔。

不同的地方在于这个题目是多个不同的串。可以想到的是,是不是可以将这些串拼接起来。

拼起来就需要考虑一个问题,找到的这个串应该要避免他们跨越了拼接的那个间隔。

所以首先我们应该要用一个原来的串中从来没有出现过的字符来分隔两个串。

其次,当我们二分寻找答案的时候,应该要考虑我们找到的这个区间,他们表示的后缀的首字母也就是sa[i],是不是分别属于n个串。

所以我们要标好每个位置属于哪个串。

 #include <iostream>
#include <set>
#include <cmath>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long LL;
#define inf 0x7f7f7f7f const int maxn = ;
int a[maxn][maxn], s[maxn * maxn], s_len[maxn], id[maxn * maxn], vis[maxn];
int sa[maxn * maxn];
int t1[maxn * maxn], t2[maxn * maxn], c[maxn * maxn];
int rnk[maxn * maxn], height[maxn * maxn];
int n, len; void build_sa(int s[], int n, int m)
{
int i, j, p, *x = t1, *y = t2;
for(i = ; i < m; i++)c[i] = ;
for(i = ; i < n; i++)c[x[i] = s[i]]++;
for(i = ; i < m; i++)c[i] += c[i - ];
for(i = n - ; i >= ; i--)sa[--c[x[i]]] = i;
for(j = ; j <= n; j <<= ){
p = ;
for(i = n - j; i < n; i++)y[p++] = i;
for(i = ; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
for(i = ; i < m; i++)c[i] = ;
for(i = ; i < n; i++)c[x[y[i]]]++;
for(i = ; i < m; i++)c[i] += c[i - ];
for(i = n - ; i >= ; i--)sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ;
x[sa[]] = ;
for(i = ; i < n; i++){
x[sa[i]] = y[sa[i - ]] == y[sa[i]] && y[sa[i - ] + j] == y[sa[i] + j] ? p - : p++;
}
if(p >= n)break;
m = p;
}
} void get_height(int s[], int n)
{
int i, j, k = ;
for(i = ; i <= n; i++)rnk[sa[i]] = i;
for(i = ; i <= n; i++){
if(k)k--;
j = sa[rnk[i] - ];
while(s[i + k] == s[j + k])k++;
height[rnk[i]] = k;
}
}
int sta[maxn * maxn], top;
bool check(int mid)
{
while(top)vis[sta[top--]] = false;
for(int i = ; i <= len; i++){
if(height[i] < mid){
while(top)vis[sta[top--]] = false;
}
if(!vis[id[sa[i]]]){
vis[id[sa[i]]] = true;
sta[++top] = id[sa[i]];
if(top == n)return true;
}
}
return false;
} int main()
{
scanf("%d", &n);
len = ;
int mmx = -;
for(int i = ; i <= n; i++){
vis[i] = false;
scanf("%d", &s_len[i]);
for(int j = ; j <= s_len[i]; j++){
scanf("%d", &a[i][j]);
if(j)mmx = max(mmx, a[i][j] - a[i][j - ]);
}
}
int mmin = inf;
for(int i = ; i <= n; i++){
for(int j = ; j <= s_len[i]; j++){
s[++len] = a[i][j] - a[i][j - ];
id[len] = i;
mmin = min(mmin, s[len]);
}
s[++len] = ++mmx;
}
for(int i = ; i <= len; i++){
s[i] = s[i] - mmin + ;
//cout<<s[i]<<endl;
} build_sa(s, len + , );
/*for(int i = 1; i <= len; i++){
cout<<sa[i]<<endl;
}*/
get_height(s, len);
/*cout<<len<<endl;
for(int i = 2; i <= len; i++){
cout<<height[i]<<endl;
}*/
//cout<<len<<endl;
int st = , ed = len, ans = -;
while(st <= ed){
int mid = (st + ed) / ;
if(check(mid)){
st = mid + ;
ans = mid;
}
else{
ed = mid - ;
}
} printf("%d\n", ans + );
return ;
}

洛谷P2463 Sandy的卡片【后缀数组】【二分】的更多相关文章

  1. BZOJ4698: Sdoi2008 Sandy的卡片(后缀数组 二分)

    题意 题目链接 Sol 不要问我为什么发两篇blog,就是为了骗访问量 后缀数组的也比较好想,先把所有位置差分,然后在height数组中二分就行了 数据好水啊 // luogu-judger-enab ...

  2. 【BZOJ-4698】Sandy的卡片 后缀数组

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

  3. 【BZOJ4698】Sdoi2008 Sandy的卡片 后缀数组+RMQ

    [BZOJ4698]Sdoi2008 Sandy的卡片 Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡 ...

  4. 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组

    题目描述 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列 ...

  5. 洛谷P3763 [Tjoi2017]DNA 【后缀数组】

    题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...

  6. BZOJ 4698: Sdoi2008 Sandy的卡片 后缀数组 + RMQ + 查分

    题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...

  7. SDOI2008 Sandy的卡片( 后缀数组 )

    求出后缀数组, 然后二分答案, 对height数组分组检验答案. 时间复杂度O(|S| log|S|) ------------------------------------------------ ...

  8. 洛谷P4051 [JSOI2007]字符加密 后缀数组

    题目链接:https://www.luogu.org/problemnew/show/P4051 思路:我们联想求后缀数组sa的过程,发现我们在求y数组的时候(第二关键字,下标为第二关键字的排位,值为 ...

  9. LG2463/BZOJ4698 「SDOI2008」Sandy的卡片 后缀数组

    问题描述 LG2463 BZOJ4698 题解 看到\(n\)个数串,一开始不太好处理,可以很容易想到把这\(n\)个数串连到一起,形成一个大串,但是每个串之间不容易处理. 经过思考,想到在每个串中间 ...

随机推荐

  1. VSCode------搭建.net core 2.0,并配置到IIS服务器

    前奏 安装VSCode最新版: https://code.visualstudio.com/ 安装window server hosting,发布和部署到IIS使用: https://www.micr ...

  2. Java获取一维数组的最小值

    编写程序,实现接受用户在文本框中输入的单行数据.这些数据都是整数数字,以空格进行分隔,空格数量不限.并将这些数据分割成一维数组,再从数组中提取最小值显示在界面中.思路是先对用户的输入进行验证,即先用t ...

  3. 反射简介—C#特性和反射

    .NET编译器的任务之一就是为所有定义和引用的类型生成元数据描述.除了程序集中标准的元数据外,.NET平台还支持特定(attribute)把更多的元数据嵌入到程序集中. .NET特性扩展了抽象的Sys ...

  4. RF-获取上个月份

    验证1: case ${NowDate} set variable 20170103 ${year} set variable ${NowDate[0:4]} ${month} set variabl ...

  5. 顶点纹理shader

    Shader "Custom/VertDisplace" { Properties { _MainTex ("Base (RGB)", 2D) = " ...

  6. Elasticseach的评分机制

    lucene 的评分机制 elasticsearch是基于lucene的,所以他的评分机制也是基于lucene的.评分就是我们搜索的短语和索引中每篇文档的相关度打分. 如果没有干预评分算法的时候,每次 ...

  7. Visual C++中去除警告

    在编程中,编译器警告的意思是提问程序员:如果这样做将会出现意外的错误,你确定要这样做吗? 在很多情况下,我们写程序的时候会出现一些警告,而这些警告我们都知道这样做的确是需要的并且程序中多处出现这种做法 ...

  8. 树莓派3b 串口通信初次尝试

    准备工作: 1. 安装wiringPi 2. 修改config.txt sudo nano /boot/config.txt 在文件的末尾添加: dtoverlay=pi3-miniuart-bt 3 ...

  9. OpenCV——轮廓面积及长度计算

    计算轮廓面积: double contourArea(InputArray contour, bool oriented=false ) InputArray contour:输入的点,一般是图像的轮 ...

  10. django进阶-modelform&admin action

    先看效果图: 登陆admin后的界面: 查看作者: 当然你也可以定制admin, 使界面更牛逼 数据库表结构: app01/models.py from django.db import models ...