【SDOI2008】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 1 2 3 4 5 9
说明/提示
数据范围:
30%的数据保证n<=50
100%的数据保证n<=1000,M<=1000,2<=Mi<=101
update:题面上数据范围mi和m的范围其实是一个东西... 真实数据范围:40<=n<=1000,2<=mi<=101,字符串中的每个数字的大小范围为[0,1864]
【题目大意】
给定 n 个序列,求 n 个序列中相同的子串的最大长度,相同的定义是给每个子串里面的每个数加上一个数等于另外一个序列
【思路描述】
首先是想到将问题转化为后缀数组进行一个字符串的操作
我们可以想到,当前后两数之差和另外一个序列中的另外相邻两数之差相等时
给前者两个数加一个相同的数就能够得到另外一个序列
所以问题就能够转化为 连续相邻两数之差相同的最长子串长度
子串,相同,数字一定属于一定范围而且比较小,好,后缀数组能写
把所有序列拼成一个序列,做成一个字符串
每个序列中间用一个不同大数隔开
然后怎么查找这个长度呢
二分这个长度
然后考虑 check 函数怎么写
比较 height [ i ] 当 i 的height [ i ] 大于长度的时候,说明这个序列符合要求
因为是按照字典序在检索,所以能够不错漏,
其实有点像是在找 height 的最小值,同时保证每个最小值在不同的序列中
当找到 n 个的时候说明每个序列都有大于等于这个长度的相同子串
没有找到的时候说明没有,
然后二分
最后输出答案,因为我们判断的是差,而第一个字符没有被判定
所以答案 + 1
【代码】
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> using namespace std; const int MAX = 1010; const int MAXM = 6010; const int MAXN = MAX * (MAXM + 1); const int DOT = 2000; int DOWN = 2000;int n = 0,num,m=-1; int a[MAX][MAXM], len[MAXM],b[MAXN]; int SA[MAXN], height[MAXN]; int rak[MAXN],id[MAXN]; int c[MAXN], x[MAXN], y[MAXN]; bool vis[MAXN]; void get_SA(int *s) {//初始化for (int i = 1; i <= n; i++)++c[x[i] = s[i]];//计算每一个字符的数量,同样的放在一起for (int i = 2; i <= m; i++)c[i] += c[i - 1];//求前缀和for (int i = n; i >= 1; i--)SA[c[x[i]]--] = i;//从后往前,这样就能求出最开始顺序for (int k = 1; k <= n; k <<= 1){int num = 0;for (int i = n - k + 1; i <= n; i++) y[++num] = i;//把最后几个字符放进去for (int i = 1; i <= n; i++)//按照顺序遍历if (SA[i] > k)//如果长度大于ky[++num] = SA[i] - k;//把第一个放进去for (int i = 1; i <= m; i++)c[i] = 0;for (int i = 1; i <= n; i++)c[x[i]]++;//x[i]是第一关键字for (int i = 2; i <= m; i++)c[i] += c[i - 1];//求前缀和for (int i = n; i >= 1; i--)SA[c[x[y[i]]]--] = y[i], y[i] = 0;swap(x, y);x[SA[1]] = 1; num = 1;for (int i = 2; i <= n; i++)x[SA[i]] = (y[SA[i]] == y[SA[i - 1]] && y[SA[i] + k] == y[SA[i - 1] + k]) ? num : ++num;if (num == n) break;m = num;}for (int i = 1; i <= n; i++)rak[SA[i]] = i;return; } void get_height(int *s) {int j, k = 0;for (int i = 1; i <= n; i++) {if (k) k--;j = SA[rak[i] - 1];while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;height[rak[i]] = k;} } int sta[MAXN]; int top = 0; bool check(int x) {while (top) vis[sta[top--]] = 0;for (int i = 1; i <= n; i++){if (height[i] < x){while(top) vis[sta[top--]] = 0;}if (!vis[id[SA[i]]]){vis[id[SA[i]]] = 1;sta[++top] = id[SA[i]];if (top == num)return 1;}}return 0; } int main() {int minn=(1<<32)-1;int r = -1;scanf("%d", &num);for (int i = 1; i <= num; i++){scanf("%d", &len[i]);r = max(r, len[i]);for (int j = 1; j <= len[i]; j++){scanf("%d", &a[i][j]);}}n = 0;for (int i = 1; i <= num; i++){for (int j = 2; j <= len[i]; j++){b[++n] = a[i][j] - a[i][j - 1]+1;id[n] = i;minn = min(b[n], minn);}b[++n] = ++DOWN;}for (int i = 1; i <= n; i++){if (minn <= 0)b[i] -= minn + 1;elseb[i]++;m = max(b[i], m);}get_SA(b);//printf("**\n"); get_height(b);//printf("**\n");int ans=0;int l = 1;while (l <= r){int mid = (l + r) >> 1;if (check(mid)){ans = mid;l = mid + 1;}else{r = mid - 1;}}//printf("**\n");printf("%d", ans+1);return 0; }
View Code
转载于:https://www.cnblogs.com/rentu/p/11410359.html
【SDOI2008】Sandy的卡片(后缀数组)相关推荐
- 【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列 ...
- 洛谷P2463 [SDOI2008]Sandy的卡片(后缀数组SA + 差分 + 二分答案)
题目链接:https://www.luogu.org/problem/P2463 [题意] 求出N个串中都出现的相同子串的最长长度,相同子串的定义如题:所有元素加上一个数变成另一个,则这两个串相同,可 ...
- [BZOJ4698][SDOI2008]Sandy的卡片(后缀自动机)
差分之后就是求多串LCS. 对其中一个串建SAM,然后把其它串放在上面跑. 对SAM上的每个状态都用f[x]记录这个状态与当前串的最长匹配长度,res[x]是对每次的f[x]取最小值.答案就是res[ ...
- 洛谷 P2463 [SDOI2008]Sandy的卡片 解题报告
P2463 [SDOI2008]Sandy的卡片 题意 给\(n(\le 1000)\)串,定义两个串相等为"长度相同,且一个串每个数加某个数与另一个串完全相同",求所有串的最长公 ...
- [SDOI2008]Sandy的卡片
题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...
- 4698: Sdoi2008 Sandy的卡片
前言 总之这个东西说起来很麻烦就是了, 思路 差分合并+后缀数组+二分(dddl) 类似于那个bzoj1031的复制子串和那个poj1743的差分 来看个例子 3 5 1 2 3 4 5 4 1 1 ...
- BZOJ4698: Sdoi2008 Sandy的卡片
题解: 裸后缀数组+二分答案 /**************************************************************Problem: 4698User: c20 ...
- Luogu P2463 [SDOI2008]Sandy的卡片
题目链接 \(Click\) \(Here\) 真的好麻烦啊..事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦..(最好是八分钟能无脑把\(SA\)码对的程度\(QAQ\) ...
- [luoguP2463] [SDOI2008]Sandy的卡片(后缀数组 + st表)
传送门 很容易想到,题目中的相同是指差分数组相同. 那么可以把差分数组连起来,中间加上一个没有出现过的且字典序小的数 双指针移动,用st表维护height数组中的最小值. 当然用单调队列应该也可以且更 ...
- 洛咕 P2463 [SDOI2008]Sandy的卡片
哈希水过. 首先这是一段delta相同的序列,按照套路差分一下,b[i]=a[i]-a[i-1],然后就是这些序列的最长公共子段 由于数据范围很小,就可以二分,枚举第一个序列的子段然后每个子序列暴力c ...
最新文章
- (已解决)IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY。Someone could be eavesdropping on you
- 子域名/目录暴力工具Gobuster
- 一个http-request的源码及改进
- Java最大公约数和最小公倍数的求法(辗转相除法)
- 论文浅尝 | 利用 RNN 和 CNN 构建基于 FreeBase 的问答系统
- matlab转dsp软件,matlab/simulink程序代写 DSP程序开发
- Oracle 学习笔记(Windows 环境下安装 + PL/SQL)
- c++类成员变量初始化详解
- 小区物业管理系统设计思想+源码
- nodejs EADDRINUSE API拒绝访问
- 计算机安装系统后鼠标无法使用,电脑重装系统后鼠标键盘不能用怎么办,鼠标键盘不能用解决方法...
- 《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机
- 你知道什么是 Figma 吧
- 微信开放平台之第三方平台开发,模板小程序如何提交?
- Powerdesigner将数据表的Name变中文,字段全部变大写
- TC358775XBG是一颗将MIPI DSI信号转换成single/ dual -link LVDS的芯片,最高分辨率支持到1920x1200
- 截图工具因为计算机无法使用,win7系统电脑自带截图工具不能用失灵了的解决方法...
- 数据治理解决方案数据治理标准化现状
- echarts 3d地图-成都
- win 7下ffmpeg平台和Android联合编译ndk rc7和ffmpeg harmony(最后还是改为r5)
热门文章
- 使用curl操作InfluxDB
- Kafka Zero-Copy 使用分析
- ibatis增删改、批量增删改以及查询
- jedis ShardedJedisPool的 HASH一致性算法(一)从String 的hashcode说起
- OOP设计思考——何时使用接口?
- extmail集群的邮件负载均衡方案 [lvs dns postfix]
- ASP.NET MVC 重点教程一周年版 第二回 UrlRouting 【转】
- nginx+tomcat的负载均衡
- 初学Flink,对Watermarks的一些理解和感悟(透彻2)
- 关于Flutter初始化流程,我必须告诉你的是...