题目链接: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. python技巧 一等函数

    函数在python中作为一等函数,具有以下特点: 1.可以作为参数传递给其他函数 2.作为其他函数的值返回 3.能赋值给变量或数据结构中的元素 4.在运行的时候创建 In [1]: def add(x ...

  2. oracle锁表

    一.锁表的处理 Oracle锁表比较简单,查询锁表的session杀掉就可以了. 1.以下几个为相关表 SELECT * FROM V$LOCK; SELECT * FROM V$SQLAREA; S ...

  3. python - str和repr方法:

    # python 内置__str__()和__repr__()方法: #显示自定制 # 示例1 # a = 123 # print(a.__str__()) # 示例2 class Test(): d ...

  4. yield函数的理解

    1.https://blog.csdn.net/qq_33472765/article/details/80839417

  5. pandas 定位 loc,iloc,ix

    In [114]: df Out[114]: A B C D 2018-06-30 0.318501 0.613145 0.485612 0.918663 2018-07-31 0.614796 0. ...

  6. python f-string

    文章目录 1. 主要内容 1.1. 旧时代的格式化字符串 1.1.1. Option #1: %-formatting 1.1.2. 怎样使用 %-formatting 1.1.3. 为什么 %-fo ...

  7. log4j2使用入门(二)——与不同日志框架的适配

    在之前博客中已经指出log4j2可以与不同的日志框架进行适配,这里举一些实际应用进行说明: 1.比如我们在项目中使用了log4j2作为日志器,使用了log4j-api2.6.2.jar和log4j-c ...

  8. kali Linux下wifi密码安全测试(1)虚拟机下usb无线网卡的挂载 【转】

    转自:http://blog.chinaunix.net/uid-26349264-id-4455634.html 目录 kali Linux下wifi密码安全测试(1)虚拟机下usb无线网卡的挂载 ...

  9. mysql启动时报错:Starting MySQL... ERROR! The server quit without updating PID file (/opt/mysql/data/mysql.pid)

    mysql启动报错Starting MySQL... ERROR! The server quit without updating PID file (/opt/mysql/data/mysql.p ...

  10. vux安装中遇到的坑

    1.输入 npm install vux --save 2.输入 npm install vux-loader --save-dev(没安装的时候,会一直报错) 3.build/webpack.bas ...