【线段树】第十三届蓝桥杯省赛C++ A组 Java C组 Python A组/B组《最长不下降子序列》(C++)

【题目描述】

给定一个长度为 N 的整数序列:,,⋅⋅⋅,

现在你有一次机会,将其中连续的 K 个数修改成任意一个相同值。

请你计算如何修改可以使修改后的数列的最长不下降子序列最长,请输出这个最长的长度。

最长不下降子序列是指序列中的一个子序列,子序列中的每个数不小于在它之前的数。

【输入格式】

输入第一行包含两个整数 N 和 K。

第二行包含 N 个整数 ,,⋅⋅⋅,

【输出格式】

输出一行包含一个整数表示答案。

【数据范围】

对于 20% 的评测用例,1≤K≤N≤100;

对于 30% 的评测用例,1≤K≤N≤1000;

对于 50% 的评测用例,1≤K≤N≤10000;

对于所有评测用例,1 ≤ K ≤ N ≤ ,1≤

【输入样例】

5 1
1 4 2 8 5

【输出样例】

4

【思路】

题解来源:AcWing 4648. 最长不下降子序列 - AcWing

【代码】

cpp 复制代码
#include <bits/stdc++.h>
const int N = 1e5 + 10;
int n, m, k, ans;
int a[N];
int b[N];       // 用于离散化的数组
int dp1[N];     // dp1[i]表示从前往后以a[i]结尾的最长不下降子序列的长度
int dp2[N];     // dp2[i]表示从前往后以a[i]开头的最长不下降子序列的长度
int find(int x) //返回整数a[i]在b数组中的下标
{
    int l = 1, r = m;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (b[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
struct
{
    int maxv;
} seg[N * 4];
void pushup(int id)
{
    seg[id].maxv = std::max(seg[id << 1].maxv, seg[id << 1 | 1].maxv);
}
void build(int id, int l, int r)
{
    if (l == r)
        seg[id].maxv = 0;
    else
    {
        int mid = l + r >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
        pushup(id);
    }
}
void change(int id, int l, int r, int pos, int val)
{
    if (l == r)
        seg[id].maxv = std::max(seg[id].maxv, val);
    else
    {
        int mid = l + r >> 1;
        if (pos <= mid)
            change(id << 1, l, mid, pos, val);
        else
            change(id << 1 | 1, mid + 1, r, pos, val);
        pushup(id);
    }
}
int query(int id, int l, int r, int ql, int qr)
{
    if (l == ql && r == qr)
        return seg[id].maxv;
    int mid = l + r >> 1;
    if (qr <= mid)
        return query(id << 1, l, mid, ql, qr);
    else if (ql >= mid + 1)
        return query(id << 1 | 1, mid + 1, r, ql, qr);
    else
        return std::max(query(id << 1, l, mid, ql, mid), query(id << 1 | 1, mid + 1, r, mid + 1, qr));
}
signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> n >> k;
    for (int i = 1; i <= n; ++i)
        std::cin >> a[i], b[i] = a[i];
    std::sort(b + 1, b + n + 1); //排序
    if (n == k)
    {
        std::cout << n << '\n';
        return 0;
    } 
    m = 1;
    for (int i = 2; i <= n; i++) //去重
        if (b[i] != b[m])
            b[++m] = b[i];
    for (int i = 1; i <= n; ++i)
        a[i] = find(a[i]);
    build(1, 1, m); //建权值线段树
    for (int i = 1; i <= n - k; ++i)
    {
        dp1[i] = query(1, 1, m, 1, a[i]) + 1;
        change(1, 1, m, a[i], dp1[i]);
    }
    build(1, 1, m); // dp1已经处理完,重新建树处理dp2
    for (int i = n; i >= k + 1; --i)
    {
        ans = std::max(ans, dp1[i - k] + k + query(1, 1, m, a[i - k], m));
        // 第一段为dp1[i-k],第二段为k,第三段为max(dp2[j]),i+k+1<=j<=n且a[j]>=a[i]
        dp2[i] = query(1, 1, m, a[i], m) + 1;
        change(1, 1, m, a[i], dp2[i]);
    }
    // 特殊情况
    for (int i = 1; i <= n - k; ++i)
        ans = std::max(ans, dp1[i] + k);
    for (int i = n; i >= k + 1; --i)
        ans = std::max(ans, dp2[i] + k);
    std::cout << ans << '\n';
    return 0;
}
相关推荐
奔跑吧 android4 小时前
【linux kernel 常用数据结构和设计模式】【数据结构 2】【通过一个案例属性list、hlist、rbtree、xarray数据结构使用】
linux·数据结构·list·kernel·rbtree·hlist·xarray
汉克老师4 小时前
第十四届蓝桥杯青少组C++选拔赛[2023.2.12]第二部分编程题(5、机甲战士)
c++·算法·蓝桥杯·01背包·蓝桥杯c++·c++蓝桥杯
Mr_Xuhhh5 小时前
项目需求分析(2)
c++·算法·leetcode·log4j
默默无名的大学生6 小时前
数据结构—顺序表
数据结构·windows
c++bug6 小时前
六级第一关——下楼梯
算法
PAK向日葵6 小时前
【C/C++】面试官:手写一个memmove,要求性能尽可能高
c语言·c++·面试
Morri36 小时前
[Java恶补day53] 45. 跳跃游戏Ⅱ
java·算法·leetcode
林木辛6 小时前
LeetCode热题 15.三数之和(双指针)
算法·leetcode·双指针
AndrewHZ6 小时前
【3D算法技术】blender中,在曲面上如何进行贴图?
算法·3d·blender·贴图·三维建模·三维重建·pcg
Jared_devin6 小时前
二叉树算法题—— [蓝桥杯 2019 省 AB] 完全二叉树的权值
数据结构·c++·算法·职场和发展·蓝桥杯