先学习下LIS最长上升子序列

​ 看了大佬的文章OTZ:最长上升子序列 (LIS) 详解+例题模板 (全),其中包含普通O(n)算法*和以LIS长度及末尾元素成立数组的普通O(nlogn)算法,当然还有本文涉及的树状数组维护后的O(nlogn)算法*

再贴一个容易理解的树状数组算法:https://www.cnblogs.com/war1111/p/7682228.html

再看看这道题

原题链接:http://acm.hnucm.edu.cn/JudgeOnline/problem.php?id=1373

题目描述

给定一个序列 a,求去除 a 中一段连续长度为 L 的序列后,a 的最长不下降子序列的长度的最大值。

输入

单组数据。

第一行两个整数 n,L 表示序列的长度为 n,L 如题意所示。

第二行 n 个数表示序列 a

n ≤ 105, 0 ≤ L ≤ n

输出

输出一个整数表示最长不下降子序列长度的最大值

样例输入

6 3

2 1 3 6 4 5

样例输出

3

思路:假设数组 dp[i] 为 以 a[i] 结尾的LIS

​ dn[i] 为 以 a[i] 结尾并截取 l 长度后的最优LIS

状态转移:

​ 1、首先应该想到在 i < L 时 dn[i] = 0;

​ 2、其次考虑 i>=L

​ ① 截取的 l 长度为 a[i-L] ~ a[i-1] 时,只需考虑把 a[i] 加在 a[1] ~ a[i-L-1] 后面,即满足条件的 dp[1] ~ dp[i-L-1] 中的最大值。 dn[i] = max { dp[j]+1 } (1 <= j < i - L , A[j] < A[i] )

​ ② 截取的 l 长度在 ①条件 之前,那么这个时候是不是可以在 dn 数组本身去找,因为前面的dn就是截取后的呀,即满足条件的 dn[1] ~ dn[i-1]中的最大值。 dn[i] = max { dn[j]+1 } (1 <= j < i , A[j] < A[i] )

​ 最后 ans 就是 dni中的最大值 <截取在 i 之前> 以及 dpi中最大<截取在 i 之后>。

dp思路类似于 蓝桥杯——最大的算式

代码实现

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5;
int a[maxn+5],dp[maxn+5],dn[maxn+5];
int main()
{
int n,k,ans=0;
scanf("%d%d",&n,&k);
for(int i=0; i<n; i++){
scanf("%d",&a[i]);
} //求 dp[i] , O(n^2)
for(int i=0; i<n; i++){
dp[i] = 1;
for(int j=0; j<i; j++){
if(a[i] >= a[j]){
dp[i] = max(dp[i],dp[j]+1);
}
}
}
//求dn[i]
for(int i=0; i<n; i++){
dn[i] = 0;
if(i>=k){
for(int j=0; j<i-k; j++)
if(a[i] >= a[j])
dn[i] = max(dn[i],dp[j]+1);
for(int j=k; j<i; j++){
if(a[i] >= a[j]){
dn[i] = max(dn[i],dn[j]+1);
}
}
ans = max(ans, dn[i]);
}
} printf("%d\n",ans);
return 0;
}

点击并拖拽以移动

​ 相信思路应该很清晰吧,对于之前做 dp 都是读完题万年懵,一看题解知天下,这道题当时能把状态转移搞清楚真的很有成就感,BUT 超时超时超时!!!

其实思路不变,按照LIS树状数组思路去做,对应的 dn[i] 也开一个对应的树状数组存储,用到了离散化,当输入值比较大则会超出树状数组范围,但是输入数量一定,就按照输入值的大小顺序及关系(大于,小于,等于)重新赋值覆盖输入值。

在hnucm平台上这道题提交了20多次测试,感谢不杀之恩orz:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int t[2][maxn],dp[maxn],dn[maxn],n,L,ans=0;
struct Node {int val,num;} a[maxn];
bool cmp(Node a,Node b){
return a.val<b.val;
}
bool cmp1(Node a,Node b){
return a.num<b.num;
} // T[x] 表示目前以数值 x 结尾的最大长度;t[0][x]对应dp[i]的树状数组,t[1][x]对应dn[i]的树状数组
int query(int p,int x){
int cnt = 0;
while(x) cnt=max(cnt,t[p][x]), x-=x&-x;
return cnt;
}
int update(int p,int x,int m){
while(x<=n) t[p][x]=max(t[p][x],m), x+=x&-x;
}
int main()
{
scanf("%d%d",&n,&L);
for(int i=1;i<=n;i++){
scanf("%d",&a[i].val);
a[i].num = i;
}
sort(a+1,a+1+n,cmp);
a[1].val = 1;
for(int i=2,k=1;i<=n;i++){
if(a[i].val==a[i-1].val) a[i].val = k;
else a[i].val = ++k;
}
sort(a+1,a+1+n,cmp1);
for(int i=1; i<=n; i++){
dp[i] = query(0,a[i].val) +1; //每次遍历的时候用 dp[i] 去查询更新当前的 T[a[i]]
update(0,a[i].val,dp[i]);
if(i>L){
dn[i] = query(1,a[i].val) +1;
update(1,a[i].val,dn[i]); //在已截取的基础上寻找LIS
update(1,a[i-L].val,dp[i-L]); //截取当前元素的前L个
ans = max(ans,dn[i]);
}
}
for(int i=1;i<=n-L;i++){ //如果截取的L在最优LIS后面,取出来没有截取的就行
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
return 0;
}

算法进阶 (LIS变形) 固定长度截取求最长不下降子序列【动态规划】【树状数组】的更多相关文章

  1. P1020 导弹拦截(nlogn求最长不下降子序列)

    题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...

  2. JDOJ 1946 求最长不下降子序列个数

    Description 设有一个整数的序列:b1,b2,…,bn,对于下标i1<i2<…<im,若有bi1≤bi2≤…≤bim 则称存在一个长度为m的不下降序列. 现在有n个数,请你 ...

  3. HDU 6357.Hills And Valleys-字符串非严格递增子序列(LIS最长非下降子序列)+动态规划(区间翻转l,r找最长非递减子序列),好题哇 (2018 Multi-University Training Contest 5 1008)

    6357. Hills And Valleys 自己感觉这是个好题,应该是经典题目,所以半路选手补了这道字符串的动态规划题目. 题意就是给你一个串,翻转任意区间一次,求最长的非下降子序列. 一看题面写 ...

  4. BZOJ2124: 等差子序列(树状数组&hash -> bitset 求是否存在长度为3的等差数列)

    2124: 等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 2354  Solved: 826[Submit][Status][Discuss ...

  5. 求最长不下降子序列(nlogn)

    最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列. 设dp[i]表示以i为结尾的最长 ...

  6. Monkey and Banana(dp,求最长的下降子序列)

    A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a bana ...

  7. [noip科普]关于LIS和一类可以用树状数组优化的DP

    预备知识 DP(Dynamic Programming):一种以无后效性的状态转移为基础的算法,我们可以将其不严谨地先理解为递推.例如斐波那契数列的递推求法可以不严谨地认为是DP.当然DP的状态也可以 ...

  8. 最长不下降子序列的O(n^2)算法和O(nlogn)算法

    一.简单的O(n^2)的算法 很容易想到用动态规划做.设lis[]用于保存第1~i元素元素中最长不下降序列的长度,则lis[i]=max(lis[j])+1,且num[i]>num[j],i&g ...

  9. 【转】关于LIS和一类可以用树状数组优化的DP 预备知识

    原文链接 http://www.cnblogs.com/liu-runda/p/6193690.html 预备知识 DP(Dynamic Programming):一种以无后效性的状态转移为基础的算法 ...

随机推荐

  1. Codeforces 1324F Maximum White Subtree DFS

    题意 给你无根一颗树,每个节点是黑色或白色.对于每一个节点,问包含该节点的权值最大的子树. 子树的权值等于子树中白点的个数减去黑点的个数. 注意,这里的子树指的是树的联通子图. 解题思路 这场就这题卡 ...

  2. Java数组实现随机生成N-M之间不重复的随机数

    接收一个整形数组,使用Math.Random每次在规定的数字范围内随机产生数字,然后嵌套for循环依次判断是否有重复值,如果有既外循环变量减一,直到把数组装满为止. /** * 随机生成 N--M的不 ...

  3. Git 不能提交空目录?我也是醉了!

    Git 不能提交空目录?我也是醉了! 背景 最近在提交文件时,因为是空的 Maven 项目结构,发现 Git 空目录死活不能提交,还以为是我自己在 .gitignore 文件中忽略了,在网上查了下,原 ...

  4. random模块的应用

  5. 程序员你是如何降低NPE的?

    程序员,如果系统突然报了一个空指针异常,你肯定像吞了一只苍蝇一样尴尬. 那么如何在日常开发过程中降低NPE? 问题 回答 现状 返回空值会出现大量的空指针异常 目的 改进方法的返回值,降低出现空指针异 ...

  6. vue项目中使用ts(typescript)入门教程

    最近项目需要将原vue项目结合ts的使用进行改造,这个后面应该是中大型项目的发展趋势,看到一篇不错的入门教程,结合它并进行了一点拓展记录之.本文从安装到vue组件编写进行了说明,适合入门. 1.引入T ...

  7. archaius(2) 配置源

    上一节讲到,archaius实现动态配置的核心就是定时去配置中心拉去配置内容,接下来几接就来看一下archaius内部具体是如何实现的. 首先我们来了解一下配置源,什么是配置源呢,archaius内部 ...

  8. CRM、用户管理权限

    CRM目录结构 from django.shortcuts import HttpResponse,render,redirect from django.conf.urls import url f ...

  9. Jackson精解第4篇-@JacksonInject与@JsonAlias注解

    Jackson是Spring Boot(SpringBoot)默认的JSON数据处理框架,但是其并不依赖于任何的Spring 库.有的小伙伴以为Jackson只能在Spring框架内使用,其实不是的, ...

  10. jstl中ftm标签用法

    <fmt:formatDate value="${dateTime}" pattern="yyyy/MM/dd HH:mm:ss"/>