题目链接: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. 记录一个PHP安装redis扩展时的问题

    安装过程:https://www.cnblogs.com/pengyunjing/p/8688320.html 由于我之前安装过该扩展,重新安装时没有执行make clean命令,所以安装好出现了下面 ...

  2. java程序运存扩容

    线上程序随着业务增多,运行的越来越慢,初步判定是因为内存分配的太小导致频繁的进行GC和OOM,于是着手增加内存上限. 增加内存上限都知道是修改java启动的opt,因为服务容器是tomcat 首先是在 ...

  3. mysql 架构 ~异地容灾

    一 简介 我们来探讨下多机房下的mysql架构二 目的:    首先要清楚你的目的     1 实现异地机房的容灾备份      2 实现异地机房的双活 三 叙说     1 实现异地机房的容灾备份  ...

  4. oracle 行号和分页

    1.行号是个伪列,rownum 永远按照默认的顺序生成 2.rownum 只能使用< <= 不能使用>  >=(原因是oracle数据库是行式数据库,像盖楼一样,没有第一层就排 ...

  5. Codeplex最流行25个开源项目

    1. VMukti富媒体协作平台 2. Microsoft SQL Server Product Samples: Engine 3. Patterns & Practices: Enterp ...

  6. python3解析库BeautifulSoup4

    Beautiful Soup是python的一个HTML或XML的解析库,我们可以用它来方便的从网页中提取数据,它拥有强大的API和多样的解析方式. Beautiful Soup的三个特点: Beau ...

  7. 简述JavaScript全局对象

    全局对象是JavaScript中非常重要的一类对象,它作为程序顶层(程序最顶端,不包括在任何函数之内)的上下文存在,JavaScript中的全局属性.全局函数都是通过全局对象来提供给程序的,比如 全局 ...

  8. C++ 字符串的编码

    转载链接:https://www.cnblogs.com/akb48/p/5439154.html windows平台 char 表示单字符,占用一个字节 wchar_t 表示宽字符,占用两个字节 L ...

  9. vsftpd控制用户禁止访问上级目录 只能访问自己目录

    涉及文件: vsftpd.conf chroot_list_file=/etc/vsftpd.chroot_list 如果设置为 chroot_local_user=YES chroot_list_e ...

  10. Linux内核驱动之延时 【转】

    转自:http://blog.chinaunix.net/uid-24219701-id-3288103.html  jiffies 计数器 定时器中断由系统定时硬件以规律地间隔产生; 这个间隔在启动 ...