【hdu】4521 小明序列【LIS变种】【间隔至少为d】
题目链接:https://vjudge.net/contest/228455#problem/B
转载于:https://blog.csdn.net/a709743744/article/details/51765252
题目大意:
求最长上升子序列,其中子序列中相邻的两个数的下标差要超过k
解题分析:
子序列中相邻的两个数的下标要超过k,要想满足这个条件我们可以按下面的思路想:
首先nlogn的LIS是毫无疑问的,然后再这个算法中,我们每次二分找到当前数的位置,如果数组中的数比当前数大的话就更新数组
所以我们可以稍微改一下上述步骤,当我们二分计算当前数的位置时,只是把当前数应该在数组中的位置保存下来,当前只更新在i - k之前的那个数,
这样我们就可以保证每次二分查找时,数组中的所有数的下标都比当前的下标少至少k.
然而我还是没有弄懂,先记录着吧。
这是我的代码,用结构体,然后套用了一下LIS模板,不知道为什WA了
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1e5 + ;
int n, d;
struct node
{
int val, ord;
}arr[MAXN],lis[MAXN]; int find(int l, int r, int key)
{
if (l == r)return l;
int mid = (l + r) >> ;
if (key>lis[mid].val)return find(mid + , r, key);
else return find(, mid, key);
} int main()
{
while (scanf("%d %d", &n, &d) != EOF){ //注意是下标之差大于d,而不是值之差大于d
memset(arr, , sizeof(arr));
for (int i = ; i <= n; i++) {
scanf("%d", &arr[i].val);
arr[i].ord = i;
}
int len = ;
for (int i = ; i <=n; i++){
if (i == )lis[++len] = arr[i];
else if (arr[i].val > lis[len].val) {
if ((arr[i].ord - lis[len].ord) > d)lis[++len] = arr[i];
}
else
{
int j = find(, len, arr[i].val);
if (j != len){
if (j == ){
if ((lis[].ord - arr[i].ord) > d)lis[j] = arr[i];
}
else{
if ((lis[j + ].ord - arr[i].ord) > d && (arr[i].ord - lis[j - ].ord) > d)
lis[j] = arr[i];
}
}
}
}
printf("%d\n", len);
}
return ;
}
AC的LIS解法
#include<iostream>
#include<cstring>
#include<cstdio>
#include <algorithm>
#define maxn 100005
using namespace std;
int a[maxn], b[maxn], p[maxn];
int n, d; int find(int p) //二分查找<=p的位置+1
{
int l, r, mid;
l = , r = n, mid = (l + r) >> ;
while (l <= r){
if (p>b[mid]) l = mid + ;
else if (p<b[mid]) r = mid - ;
else return mid;
mid = (l + r) >> ;
}
return l;
} int LIS(){
int i, j, ans = ;
for (i = ; i <= n; i++){
p[i] = find(a[i]); //p[i]存的是a[i]在上升数组中的位置
ans = max(ans, p[i]);
j = i - d;
if (j>) b[p[j]] = min(b[p[j]], a[j]);
}
return ans;
} int main()
{
int i, res;
while (cin >> n >> d){
for (i = ; i <= n; i++){
scanf("%d", &a[i]);
b[i] = maxn;
}
res = LIS();
printf("%d\n", res);
}
return ;
}
dp AC解法
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = + ;
int a[maxn], dp[maxn], g[maxn], n, k; int main()
{
while (~scanf("%d%d", &n, &k))
{
int ans = -;
memset(dp, , sizeof(dp));
memset(g, INF, sizeof(g));
for (int i = ; i <= n; i++)
scanf("%d", &a[i]);
for (int i = ; i <= n; i++)
{ //延迟p位更新 //为什么我感觉i>k+1以后还是连续的,下标并没有相差k啊???搞不懂
if (i - k - >) g[dp[i - k - ]] = min(a[i - k - ], g[dp[i - k - ]]); // i-p>1 是因为下标j范围为1<j<=m
dp[i] = lower_bound(g + , g + + n, a[i]) - g; //先记录下a[i]在g数组中的位置
ans = max(ans, dp[i]);
}
cout << ans << endl;
}
return ;
}
2018-05-17
【hdu】4521 小明序列【LIS变种】【间隔至少为d】的更多相关文章
- hdu4521 小明系列的问题——小明序列(LIS变种 (段树+单点更新解决方案))
链接: huangjing 题目:中文题目 思路: 1:这个题目假设去掉那个距离大于d的条件,那么必定是一个普通的LIS.可是加上那个条件后就变得复杂了.我用的线段树的解法. . .就是採用延迟更新的 ...
- hdu 4521 小明序列(线段树,DP思想)
题意: ①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 : ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ...
- hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)
小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Tot ...
- hdu 4521 小明系列问题——小明序列 线段树+二分
小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Pro ...
- HDU 4521 小明系列问题——小明序列 (线段树 单点更新)
题目连接 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来 ...
- 小明系列问题――小明序列(LIS)
小明系列问题――小明序列 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit ...
- 小明系列问题——小明序列(Lis 相距大于d的单调上升子序列)
小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Tot ...
- hdu 4521 小明系列问题——小明序列(线段树 or DP)
题目链接:hdu 4521 本是 dp 的变形,却能用线段树,感觉好强大. 由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时.所以用线段树进行优化.线段树维护的是区间内 ...
- HDU 4521 小明系列问题——小明序列 (线段树维护DP)
题目地址:HDU 4521 基本思路是DP.找前面数的最大值时能够用线段树来维护节省时间. 因为间隔要大于d. 所以能够用一个队列来延迟更新,来保证每次询问到的都是d个之前的. 代码例如以下: #in ...
随机推荐
- CF875F Royal Questions
传送门 似乎可以按边权排序后二分图匹配 这里给一个复杂度稳定的算法 把一个公主能匹配的两个点连边,然后依次加边,每当加到一个大小为\(n\)的连通块中有\(n\)条边之后,这时形成了基环树,将这些边定 ...
- [BJWC2011]最小三角形(分治+最近点对)
题面:BJWC2011 最小三角形 \(solution:\) 昨天才学完平面最近点对,今天就要求平面最近的三个点,显然不是巧合. 仔细一思考,我们用来求平面最近点对的方法不就可以用到三个点上吗? 就 ...
- TCP网络协议通信原理(客户端和服务器端)
下面直接用代码来说明TCP协议的基础知识: 服务器端代码块: from socket import * from time import ctime ''' 指定主机地址.工作端口号.接收缓存的长度 ...
- 边沿检测方法-FPGA入门教程
本节实验主要讲解FPGA开发中边沿检测方法,我们在设计中会经常用到.这个地方大家一定要理解. 1.1.1.原理介绍 学习HDL语言设计与其他语言不一样,HDL语言设计需要考虑更多的信号的电气特性,时序 ...
- emmc基础技术8:操作模式4-data transfer mode
1.前言 eMMC总线操作包含: boot mode, device identification mode interrupt mode data transfer mode 本文主要描述data ...
- kafka系列四、kafka架构原理、高可靠性存储分析及配置优化
一.概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统,后成为Apache的一部分,它使用Scala编写,以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cl ...
- SQLServer语言之DDL,DML,DCL,TCL
数据库语言分类 SQLServer SQL主要分成四部分: (1)数据定义.(SQL DDL)用于定义SQL模式.基本表.视图和索引的创建和撤消操作. (2)数据操纵.(SQL DML)数据操纵分 ...
- oracle 视图 参数
创建包: create or replace package p_view_param is function set_param(num number) return number; fu ...
- VS2017编译boost库
1.http://www.boost.org/ 下载boost库. 2.解压到 D:\ProgramFiles\boost 3.环境配变量配置 VS2017更加注重跨平台性,安装文件较 ...
- input text 去掉标签下拉提示
autocomplete 属性 autocomplete 属性规定输入字段是否应该启用自动完成功能. 自动完成允许浏览器预测对字段的输入.当用户在字段开始键入时,浏览器基于之前键入过的值,应该显示出在 ...