题目链接: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】的更多相关文章

  1. hdu4521 小明系列的问题——小明序列(LIS变种 (段树+单点更新解决方案))

    链接: huangjing 题目:中文题目 思路: 1:这个题目假设去掉那个距离大于d的条件,那么必定是一个普通的LIS.可是加上那个条件后就变得复杂了.我用的线段树的解法. . .就是採用延迟更新的 ...

  2. hdu 4521 小明序列(线段树,DP思想)

    题意: ①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 : ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ...

  3. hdu 4521 小明系列问题——小明序列(线段树+DP或扩展成经典的LIS)

    小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...

  4. hdu 4521 小明系列问题——小明序列 线段树+二分

    小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Pro ...

  5. HDU 4521 小明系列问题——小明序列 (线段树 单点更新)

    题目连接 Problem Description 大家都知道小明最喜欢研究跟序列有关的问题了,可是也就因为这样,小明几乎已经玩遍各种序列问题了.可怜的小明苦苦地在各大网站上寻找着新的序列问题,可是找来 ...

  6. 小明系列问题――小明序列(LIS)

    小明系列问题――小明序列 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit ...

  7. 小明系列问题——小明序列(Lis 相距大于d的单调上升子序列)

    小明系列问题——小明序列 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...

  8. hdu 4521 小明系列问题——小明序列(线段树 or DP)

    题目链接:hdu 4521 本是 dp 的变形,却能用线段树,感觉好强大. 由于 n 有 10^5,用普通的 dp,算法时间复杂度为 O(n2),肯定会超时.所以用线段树进行优化.线段树维护的是区间内 ...

  9. HDU 4521 小明系列问题——小明序列 (线段树维护DP)

    题目地址:HDU 4521 基本思路是DP.找前面数的最大值时能够用线段树来维护节省时间. 因为间隔要大于d. 所以能够用一个队列来延迟更新,来保证每次询问到的都是d个之前的. 代码例如以下: #in ...

随机推荐

  1. oracle存储过程,sql语句执行时间

    create or replace procedure sum_info is i integer; temp1 varchar2(50); temp2 varchar2(50); t1 date; ...

  2. 简单透彻理解JSONP原理及使用

    首先提一下JSON这个概念,JSON是一种轻量级的数据传输格式,被广泛应用于当前Web应用中.JSON格式数据的编码和解析基本在所有主流语言中都被实现,所以现在大部分前后端分离的架构都以JSON格式进 ...

  3. pyppeteer爬虫例子

    如果在centos上使用,需要安装下面的依赖 yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x8 ...

  4. springboot系列十、springboot整合redis、多redis数据源配置

    一.简介 Redis 的数据库的整合在 java 里面提供的官方工具包:jedis,所以即便你现在使用的是 SpringBoot,那么也继续使用此开发包. 二.redidTemplate操作 在 Sp ...

  5. 基于 OpenSSL 的 CA 建立及证书签发

    http://rhythm-zju.blog.163.com/blog/static/310042008015115718637/ 建立 CA 建立 CA 目录结构 按照 OpenSSL 的默认配置建 ...

  6. centos7.2环境编译安装mysql5.5.48

    一.安装cmake编译工具 跨平台编译器 查看是否已经安装了gcc # rpm -qa | grep gcc # yum install -y gcc-c++ # yum install -y cma ...

  7. WampServer配置

    本机php环境搭建教程:windows环境下wampserver的配置教程--超级详细 对于初做PHP网站的朋友来说,第一步肯定是希望在自己电脑是搭建PHP环境,省去空间和上传的麻烦!但搭建环境也不是 ...

  8. C++ code:判断字符串相等

    如果两个字符串中0和1的个数分别相等,则称该对字符串为相等. 方法一: 由于string类对于读取文件中子串以及比较都很方便,所以,用string类的对象来逐对存放字串,然后将字串分别排序后对其进行比 ...

  9. wpf 用户自定义事件传参2

    public delegate void MenuButtonClickEventHandler(object sender, EventArgs e); public event MenuButto ...

  10. 【ES】学习2-搜索

    1.空搜索 返回所有索引下的所有文档 GET /_search 设置超时.timeout 不是停止执行查询,它仅仅是告知正在协调的节点返回到目前为止收集的结果并且关闭连接.在后台,其他的分片可能仍在执 ...