最长不下降子序列(线段树优化dp)
最长不下降子序列
题目大意:
给定一个长度为 N 的整数序列:A\(_{1}\),A\(_{2}\),⋅⋅⋅,A\(_{N}\)。
现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值。
请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。
最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。
题目思路:
我们考虑这样两个数组,f[ ],g[ ],分别表示以i为结尾的最长不下降子序列长度和以i为开始的最长子序列长度,那我们的答案如果在不考虑修改k个数这个条件时,我们的答案就是:f[i]+g[i]-1;
当我们再去考考虑修改k个连续数这个条件时,答案就变成了:max(\(\sum_{i = n}^{i-k>=1}\)f[i-k]+k+g[i],k);
这个答案可以被看为由三部分组成:f[i-k]以i-k为结尾 + 修改后的k个数 + g[i]以i为开始
所以在实现上我们考虑用权值线段树来优化寻找最长不下降子序列这个过程
权值线段树维护的是以离散化后的点为(结束/开始)的最长不下降子序列长度
先将原数据去重+离散化
然后先处理f[i] =query(1,1,tot,1,a[i])+1 ,每次查询query(1,1,tot,1,a[i]),查询在他之前的最长子序列,之后将f[i]插入a[i]的位置
例如:a[i]离散化以后为3,那我们此时的查询即为query(1,1,tot,1,3)
这样我们就是查询从1到3的最长不下降子序列,修改也是同理,将3的值改为max(val,f[i])
之后重建线段树,倒着处理g[i]
几乎是同样的方法,只不过在这个同时处理一下ans = max(ans,f[i-k]+k+g[i]);
代码实现:
# include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
#define ls u<<1
#define rs u<<1|1
int f[N],g[N];//f[]--以i为结尾的最长...,g[]--以i为开始的最长...
int a[N];
int n,k;
struct seg{
int maxn[4*N];
void pushup(int u){
maxn[u] = max(maxn[ls],maxn[rs]);
}
void build(int u,int l,int r){
if(l == r){
maxn[u] = 0;
return;
}
int mid = l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,int pos,int val){
if(l == r){
maxn[u] = max(maxn[u],val);
return;
}
int mid = l+r>>1;
if(pos<=mid) modify(ls,l,mid,pos,val);
else modify(rs,mid+1,r,pos,val);
pushup(u);
}
int query(int u,int l,int r,int L,int R){
if(l==L&&r==R){
return maxn[u];
}
int mid = l+r>>1;
if(R<=mid) return query(ls,l,mid,L,R);
else if(L>mid) return query(rs,mid+1,r,L,R);
else return max(query(ls,l,mid,L,mid),query(rs,mid+1,r,mid+1,R));
}
}tr;
int b[N],tot;
int find(int u){
int l = 1,r = tot;
int ans;
while(l<r){
int mid = l+r>>1;
if(b[mid] >= u){
r = mid;
}
else l = mid+1;
}
return l;
}
int main(){
cin>>n>>k;
for(int i = 1;i <= n;++i) {
cin>>a[i];
b[i] = a[i];
}
sort(b+1,b+1+n);
tot = 1;
for(int i = 2;i <= n;++i)//离散化+去重
{
if(b[i] != b[tot]){
b[++tot] = b[i];
}
}
for(int i = 1;i <= n;++i)
{
a[i] = find(a[i]);
}
tr.build(1,1,tot);//处理f[i]
for(int i = 1;i <= n-k;++i){
f[i] = tr.query(1,1,tot,1,a[i])+1;
tr.modify(1,1,tot,a[i],f[i]);
}
tr.build(1,1,tot);//处理完f[i]后重建线段树来啊处理g[i]
int ans = 0;
for(int i = n;i-k>=1;--i){
ans = max(ans,f[i-k]+k+tr.query(1,1,tot,a[i-k],tot));
g[i] = tr.query(1,1,tot,a[i],tot)+1;
tr.modify(1,1,tot,a[i],g[i]);
}
cout<<ans<<endl;
return 0;
}
最长不下降子序列(线段树优化dp)的更多相关文章
- BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】
BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...
- [AGC011F] Train Service Planning [线段树优化dp+思维]
思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...
- Codeforces Round #426 (Div. 2) D 线段树优化dp
D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...
- 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp
题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...
- POJ 2376 Cleaning Shifts (线段树优化DP)
题目大意:给你很多条线段,开头结尾是$[l,r]$,让你覆盖整个区间$[1,T]$,求最少的线段数 题目传送门 线段树优化$DP$裸题.. 先去掉所有能被其他线段包含的线段,这种线段一定不在最优解里 ...
- 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$
正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...
- D - The Bakery CodeForces - 834D 线段树优化dp···
D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...
- 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点
容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...
- Codeforces 1603D - Artistic Partition(莫反+线段树优化 dp)
Codeforces 题面传送门 & 洛谷题面传送门 学 whk 时比较无聊开了道题做做发现是道神题( 介绍一种不太一样的做法,不观察出决策单调性也可以做. 首先一个很 trivial 的 o ...
随机推荐
- [NOI P模拟赛] 传统艺能(子序列自动机、矩阵乘法,线段树)
(2:00)OID:"完了,蓝屏了!"(代码全消失) 众人欢呼 OID:开机,"原题测试--" (30min later)OID 开始传统艺能: " ...
- [CF1527D] MEX Tree (lca)
题面 给你一棵 n n n 个结点的树,对于所有的 k ∈ [ 0 , n ] k\in[0,n] k∈[0,n] ,求出 M E X = k {\rm MEX}=k MEX=k 的路径数量. 一条路 ...
- 1.6_HTML基础属性
name 属性 name 属性用于指定标签元素的名称. <a> 标签内必须提供 href 或 name 属性. <a name="value"> id 属性 ...
- 【java】学习路径21-基本类型的包装类
int i =100; //Integer i2 = new Integer(100); //我们发现已被弃用,现在我们一般的方法是使用valueOf Integer i2 = null; i2 = ...
- KingbaseES V8R6集群维护案例之---停用集群node_export进程
案例说明: 在KingbaseES V8R6集群启动时,会启动node_exporter进程,此进程主要用于向kmonitor监控服务输出节点状态信息.在系统安全漏洞扫描中,提示出现以下安全漏洞: 对 ...
- Liquibase-数据库版本管理控制
1. 简介 Liquibase是一个用于跟踪.管理和应用数据库变化的开源的数据库重构工具.它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制. Liquibase使参与应用程序发 ...
- [DOM]获取元素:根据ID、标签名、HTML5新增的方法、特殊元素获取
目录 [DOM]获取元素:根据ID.标签名.HTML5新增的方法.特殊元素获取 1.根据 ID 获取[.getElementById( )] 2.根据标签名获取[.getElementsByTagNa ...
- python基础__十大经典排序算法
用Python实现十大经典排序算法! 排序算法是<数据结构与算法>中最基本的算法之一.排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大, ...
- 重新安装kuboard后,原先配置的CI/CD命令都没了,需要重新创建
背景介绍 使用如下命令创建的kuboard服务,上一层用nginx设置代理,用域名访问使用的 docker run -d \ --restart=always \ --name=kuboard \ - ...
- RabbitMQ各个端口被占用的进程说明
官方地址:https://www.rabbitmq.com/networking.html#ports 端口 描述 4369 erlang 发现端口,被 epmd 占用,用于 RabbitMQ 节点和 ...