最长不下降子序列(线段树优化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 ...
随机推荐
- 【ARK UI】HarmonyOS 从相册选择图片并显示到Image组件上
参考资料 [Harmony OS][ARK UI]ETS 上下文基本操作 [Harmony OS][ARK UI]ets使用startAbility或startAbilityForResult方式 ...
- 【MySQL】从入门到精通7-设计多对多数据库
上期:[MySQL]从入门到精通6-MySQL数据类型与官方文档 第一章:理解 和一对多不一样,多对多意思是,一个数据可以被不同的数据关联. 如果是一对多,我们还可以用外键来达成. 但是现在我们是多对 ...
- 03_Django-GET请求和POST请求-设计模式及模板层
03_Django-GET请求和POST请求-设计模式及模板层 视频:https://www.bilibili.com/video/BV1vK4y1o7jH 博客:https://blog.csdn. ...
- 一文学会Spring JDBC 使用
Spring JDBC 1.JDBC JDBC 就是 数据库开发 操作的 代名词,因为只要是现代商业项目的开发那么一定是离不开 数据库 的,不管你搞的是什么,只要是想使用动态的开发结构,那么一定就是 ...
- Java中的Optional
在我们日常的开发中,我们经常会遇到 NullPointerException.如何才能优雅的处理NPE?这里告诉大家一个较为流行的方法 java.util.Optional 使用Optional来修饰 ...
- Java SE 16 record 类型说明与使用
Java SE 16 record 类型说明与使用 作者:Grey 原文地址: 博客园:Java SE 16 record 类型说明与使用 CSDN:Java SE 16 record 类型说明与使用 ...
- 关于标签k8s训练营文章的转载声明
该标签下的所有文章都转载自 https://www.qikqiak.com/k8strain/
- 使用读写分离模式扩展 Grafana Loki
转载自:https://mp.weixin.qq.com/s?__biz=MzU4MjQ0MTU4Ng==&mid=2247500127&idx=1&sn=995987d558 ...
- Docker 数据共享与持久化
- Elasticsearch:运用 shard_size 来提高term aggregation的精度