首页 > 其他分享 >最长不下降子序列(线段树优化dp)

最长不下降子序列(线段树优化dp)

时间:2022-11-01 13:33:12浏览次数:81  
标签:int 线段 mid tot 序列 query 最长 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;
}

标签:int,线段,mid,tot,序列,query,最长,dp
From: https://www.cnblogs.com/empty-y/p/16847360.html

相关文章

  • 学习笔记-JAVA反序列化
    JAVA反序列化免责声明本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关.简介序列化是让Java对象脱离Java运......
  • 扫描线-线段树
    求面积并#include<bits/stdc++.h>usingnamespacestd;typedeflonglongLL;constintN=1e6+10;intn;intX[N*2];structsegment{ intl,r,h,val;}seg[N*2]......
  • CF1743E FTL(哈希,DP)——关于 xorshift 的哈希冲突
    CF1743EFTL有两把laser枪,一把伤害\(p_0\)两发间隔时间至少\(t_0\),另一把\(p_1,t_1\)。打敌方太空船,血量\(N\)防御值\(s\),如果某个时刻你对太空船打出\(P\)的......
  • DP问题概述
    DP路径问题DP的关键问题在于寻找整个问题当中是否存在(初始状态,转移状态,状态转移方程)等等关键的key,当我们能够寻找到这些key的时候,那么本问题也能够用dp解决。DP关键在......
  • Java实现 Serializable 序列化
    深度理解Java实现Serializable序列化概念把对象转换为直接序列的过程叫对象的序列化把字节序列恢复为对象的过程叫对象的反序列化用途对象持久化跨网络数据交换,远程过程调......
  • Unity反序列天气API的JSON
    心知天气:https://www.seniverse.com/JSON:{"results":[{"location":{"id":"C23NB62W20TF","name":"西雅图","country":......
  • 一台虚拟机,基于docker搭建大数据HDP集群
    前言好多人问我,这种基于大数据平台的xxxx的毕业设计要怎么做。这个可以参考之前写得关于我大数据毕业设计的文章。这篇文章是将对之前的毕设进行优化。个人觉得可以分为......
  • PHP反序列化做题方法
    1.简化:把PHP代码复制到编辑器里面,寻找PHP反序列化的魔术方法,然后把不需要的部分删去2.找链子:通过以知的魔术方法,寻找到可以利用的点,然后想办法通过对象与方法的调用执行......
  • tcp与udp缓冲区大小总结
    1.tcp收发缓冲区默认值[root@localhost/]#cat/proc/sys/net/ipv4/tcp_rmem409687380419430487380:tcp接收缓冲区的默认值[root@localhost/]#cat/proc......
  • 最长公共上升子序列
      n^3#include<iostream>#include<algorithm>#include<cstring>#include<vector>usingnamespacestd;constintN=600;intn,m,a[N],b[N],f[N][N];i......