洛谷P2463 Sandy的卡片【后缀数组】【二分】
题目描述
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,表示可以获得的最高等级。
输入输出样例
2 2 1 2 3 4 5 9
2
说明
数据范围:
30%的数据保证n<=50
100%的数据保证n<=1000,M<=1000,2<=Mi<=101
题意:
给定几串序列,问他们最长公共子序列是多长。
思路:
类似之前做的Muisical, Themehttps://www.cnblogs.com/wyboooo/p/9865919.html
都是可以通过增加一个定值,所以只需要处理间隔。
不同的地方在于这个题目是多个不同的串。可以想到的是,是不是可以将这些串拼接起来。
拼起来就需要考虑一个问题,找到的这个串应该要避免他们跨越了拼接的那个间隔。
所以首先我们应该要用一个原来的串中从来没有出现过的字符来分隔两个串。
其次,当我们二分寻找答案的时候,应该要考虑我们找到的这个区间,他们表示的后缀的首字母也就是sa[i],是不是分别属于n个串。
所以我们要标好每个位置属于哪个串。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 using namespace std; 11 typedef long long LL; 12 #define inf 0x7f7f7f7f 13 14 const int maxn = 1005; 15 int a[maxn][maxn], s[maxn * maxn], s_len[maxn], id[maxn * maxn], vis[maxn]; 16 int sa[maxn * maxn]; 17 int t1[maxn * maxn], t2[maxn * maxn], c[maxn * maxn]; 18 int rnk[maxn * maxn], height[maxn * maxn]; 19 int n, len; 20 21 void build_sa(int s[], int n, int m) 22 { 23 int i, j, p, *x = t1, *y = t2; 24 for(i = 0; i < m; i++)c[i] = 0; 25 for(i = 0; i < n; i++)c[x[i] = s[i]]++; 26 for(i = 1; i < m; i++)c[i] += c[i - 1]; 27 for(i = n - 1; i >= 0; i--)sa[--c[x[i]]] = i; 28 for(j = 1; j <= n; j <<= 1){ 29 p = 0; 30 for(i = n - j; i < n; i++)y[p++] = i; 31 for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j; 32 for(i = 0; i < m; i++)c[i] = 0; 33 for(i = 0; i < n; i++)c[x[y[i]]]++; 34 for(i = 1; i < m; i++)c[i] += c[i - 1]; 35 for(i = n - 1; i >= 0; i--)sa[--c[x[y[i]]]] = y[i]; 36 swap(x, y); 37 p = 1; 38 x[sa[0]] = 0; 39 for(i = 1; i < n; i++){ 40 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + j] == y[sa[i] + j] ? p - 1 : p++; 41 } 42 if(p >= n)break; 43 m = p; 44 } 45 } 46 47 void get_height(int s[], int n) 48 { 49 int i, j, k = 0; 50 for(i = 0; i <= n; i++)rnk[sa[i]] = i; 51 for(i = 1; i <= n; i++){ 52 if(k)k--; 53 j = sa[rnk[i] - 1]; 54 while(s[i + k] == s[j + k])k++; 55 height[rnk[i]] = k; 56 } 57 } 58 int sta[maxn * maxn], top; 59 bool check(int mid) 60 { 61 while(top)vis[sta[top--]] = false; 62 for(int i = 1; i <= len; i++){ 63 if(height[i] < mid){ 64 while(top)vis[sta[top--]] = false; 65 } 66 if(!vis[id[sa[i]]]){ 67 vis[id[sa[i]]] = true; 68 sta[++top] = id[sa[i]]; 69 if(top == n)return true; 70 } 71 } 72 return false; 73 } 74 75 int main() 76 { 77 scanf("%d", &n); 78 len = 0; 79 int mmx = -1; 80 for(int i = 1; i <= n; i++){ 81 vis[i] = false; 82 scanf("%d", &s_len[i]); 83 for(int j = 1; j <= s_len[i]; j++){ 84 scanf("%d", &a[i][j]); 85 if(j)mmx = max(mmx, a[i][j] - a[i][j - 1]); 86 } 87 } 88 int mmin = inf; 89 for(int i = 1; i <= n; i++){ 90 for(int j = 2; j <= s_len[i]; j++){ 91 s[++len] = a[i][j] - a[i][j - 1]; 92 id[len] = i; 93 mmin = min(mmin, s[len]); 94 } 95 s[++len] = ++mmx; 96 } 97 for(int i = 1; i <= len; i++){ 98 s[i] = s[i] - mmin + 1; 99 //cout<<s[i]<<endl; 100 } 101 102 build_sa(s, len + 1, 2000); 103 /*for(int i = 1; i <= len; i++){ 104 cout<<sa[i]<<endl; 105 }*/ 106 get_height(s, len); 107 /*cout<<len<<endl; 108 for(int i = 2; i <= len; i++){ 109 cout<<height[i]<<endl; 110 }*/ 111 //cout<<len<<endl; 112 int st = 0, ed = len, ans = -1; 113 while(st <= ed){ 114 int mid = (st + ed) / 2; 115 if(check(mid)){ 116 st = mid + 1; 117 ans = mid; 118 } 119 else{ 120 ed = mid - 1; 121 } 122 } 123 124 printf("%d\n", ans + 1); 125 return 0; 126 }
转载于:https://www.cnblogs.com/wyboooo/p/9876295.html
洛谷P2463 Sandy的卡片【后缀数组】【二分】相关推荐
- 洛谷 P4094 [HEOI2016/TJOI2016]字符串 后缀数组+二分+主席树
题目链接 后缀数组 题目分析: sa[i] – 第i小的后缀的编号 rank[i] --编号为i的后缀排第几: height[i] – 第i和第i-1的最长lcp最长公共前缀: 1.二分答案,答案肯定 ...
- 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列 ...
- 洛谷P3763 [Tjoi2017]DNA 【后缀数组】
题目链接 洛谷P3763 题解 后缀数组裸题 在BZOJ被卡常到哭QAQ #include<algorithm> #include<iostream> #include< ...
- 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)
题目链接:https://www.luogu.org/problem/P2463 [题意] 求出N个串中都出现的相同子串的最长长度,相同子串的定义如题:所有元素加上一个数变成另一个,则这两个串相同,可 ...
- 洛谷 P2463 [SDOI2008]Sandy的卡片 解题报告
P2463 [SDOI2008]Sandy的卡片 题意 给\(n(\le 1000)\)串,定义两个串相等为"长度相同,且一个串每个数加某个数与另一个串完全相同",求所有串的最长公 ...
- bzoj3998/洛谷3975 [TJOI2015]弦论 (后缀自动机)
bzoj3998/洛谷3975 [TJOI2015]弦论 题意:求第 k 小字串 方法:先建立SAM,和上一题一样按照拓扑序求出size(表示这个串出现的次数).这道题我们需要求第 k 小,所以我们还 ...
- HDU - 5030 Rabbit's String(后缀数组+二分)
题目链接:点击查看 题目大意:给出一个字符串,现在要求将其分为不大于k个连续的子串,对于每个子串求出字典序最大的子串,现在要求所有子串的最大子串的最大值最小,输出这个最大子串 题目分析:最大值最小,标 ...
- HDU - 5008 Boring String Problem(后缀数组+二分)
题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...
- bzoj3277 串 (后缀数组+二分答案+ST表)
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
最新文章
- L2-009. 抢红包 结构体排序
- 详解动态规划最长公共子序列--JavaScript实现
- JVM笔记 3 3 垃圾回收算法
- Git学习笔记:远程仓库
- 【Linux】一步一步学Linux——group文件详解(108)
- HTML <cite> 标签
- 406(浏览器接收的响应类型和服务器返回的响应类型不匹配)
- pythonrandrange_Python3 randrange() 函数
- 合肥工业大学机器人技术期末_机器人技术第三次作业(HFUT)
- Oracle 数据块 Block 说明
- Python中的图灵机器人
- unknown error: Chrome failed to start: crashed 解决方法
- Freemarker获取项目根目录
- 苹果自带的清理软件_苹果电脑清理软件哪个好|电脑|苹果电脑|mac|旧文件
- Linux下使用锐捷客户端连接网络,以及遇到的问题
- c#明华rf读卡器_明华URF-R330读卡器C#代码示例
- android ios开发难度对比,ios VS android:这不就是简洁与复杂最明显的对比
- javaweb项目实训总结_JAVAWEB实训心得体会
- 网卡 promiscuous mode 与 MAC 的一些 filter 功能
- 华师大计算机基础在线作业,华东师范大学计算机作业答案
热门文章
- python谁是卧底游戏流程图_虎牙小程序—谁是卧底 |明星互动游戏
- APP技巧:微信中这6个设置建议关闭,可以防止个人信息或将全暴露,赶快看一看吧!...
- 30个Python极简代码,10分钟get常用技巧!
- 原来Github上也有这么多的JavaScript学习资源!
- word文本样式代码样式_使用文本样式表达创建真相来源
- 关于MFC遇到的一系列类型转换问题
- spring boot druid 监控没有sql记录
- .net core高性能通讯开源组件BeetleX
- 简述 Spring Cloud 是什么
- CenterOS 7安装Nginx