当前位置: 首页 > news >正文

【CF】Day78——⭐Codeforces Round 876 (Div. 2) D (LIS | 思维 | DP)

D. Ball Sorting

题目:

思路:

思路想到了LIS,但是不知道怎么dp

我们先假设没有 k 的限制,即有无限个 0,那么此时的最优解是什么呢?

显然就是 n - len,其中 len 为LIS的长度,为什么呢?(以下的LIS代表递增子序列)

因为由于每次操作我们都可以将数插到任意位置,那么显然我们每一个数最多只需要移动一次即可到正确位置,那么如果有 k 这个限制呢?

首先从上面的结论我们可以知道,如果答案是 n - len,那么 0 的数量就得是 LIS 中间的断开区间的个数,什么意思呢?

我们举个例子,假设数组是 2 3 1 4 6 5,那么LIS就是 2 3 4 6 或 2 3 4 5,那么我们要将 1 5 放到正确位置的话就要 2 个 0(最少操作步数),如果只有 1 个 0 我们怎么分配呢?

 

我这里举例两种方式,一个是将整个区间重新排,一个是将 1 4 6 5 重新排(即绿色括号内的数)

那么答案就是绿色括号内区间的长度,这里的绿色括号就是 0 ,因为 0 可以排好任意一个区间内的所有数,所以我们显然是框选的数越少越好,那么做法就初见雏形

我们可以枚举每一个 k,即 0 的个数,然后考虑dp,那么如何dp呢?

我们可以定义 dp[i][j] 为有 i 个 0 时,LIS在 j 结尾时的最少操作数,那么如何转移呢?

首先一个显然的转移就是 dp[i][j] = dp[i-1][j],即直接从上一层转移过来

那么考虑另一个特殊情况,如果 a[i] > a[i-1] 那么 a[i] 就可以直接接在前面的 LIS 后面,且不会增加奉献,那么就有 dp[i][j] = min(dp[i][j],dp[i][j-1])

然后考虑暴力,由于我们不知道当前这个 j 当作哪个 LIS 的后面一个数奉献最少,所以直接暴力枚举前面每一种可能,我们从 0 ~ j - 1暴力寻找,如果有 a[j] > a[k] 说明我们的 j 可以当作 k 位置结尾的LIS的后一个数,如 2 3 后面可以接上 4,那么考虑奉献

如果我们选择接上去了,那么中间的数肯定都要被操作掉,如 2 3 (1) 4 ,其奉献就是 1,即LIS中间的数的个数,表示出来就是 j - k - 1,转移方程就是 dp[i][j] = min(dp[i][j], dp[i-1][k] + j - k - 1)

总结做法:考虑如何让操作最小,我们肯定是选择不需要动的数越多越好,那么就考虑LIS,对于一个LIS,由于 0 可以操作任意长度的区间,那我们考虑将 0 插入 LIS 的断开位置,那么奉献就是LIS所有断开区间的长度,显然可以考虑 dp 做法,因为我们不知道选哪个 LIS 最好

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int n;cin >> n;vector<int> a(n+2);a[0] = 0, a[n + 1] = n + 1;for (int i = 1; i <= n; i++){cin >> a[i];}vector<vector<int>> dp(n + 1, vector<int>(n + 2, 1e18));//初始化一下 i = 0 时的情况,即看看不能跳时的最长LISdp[0][0] = 0;for (int i = 1; i <= n+1; i++){if (a[i] > a[i - 1])dp[0][i] = dp[0][i - 1];else break;}//枚举有 i 个 0 且LIS结尾在第 j 个数的最少操作数 for (int i = 1; i <= n; i++){for (int j = 1; j <= n+1; j++){//可以从上一个 i 转移过来dp[i][j] = dp[i - 1][j];//如果当前数可以直接连接前一个 LISif (a[j] > a[j-1]){//那就取 mindp[i][j] = min(dp[i][j], dp[i][j - 1]);}//枚举可以从哪个点拼接过来for (int k = 0; k < j; k++){//如果可以拼接,那么合并完后区间内的数就都要被操作if (a[j] > a[k]){//跳跃的奉献就是区间内的数的个数,即 j - k - 1,然后取mindp[i][j] = min(dp[i - 1][k] + j - k - 1, dp[i][j]);}}}cout << dp[i][n + 1] << " ";}cout << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

相关文章:

  • 15-Oracle 23ai Vector Search Similarity Search-向量相似性和混合搜索-实操
  • go工具库:hertz api框架 hertz client的使用
  • 【数据结构】详解算法复杂度:时间复杂度和空间复杂度
  • 使用python实现奔跑的线条效果
  • TTL简述
  • 基于算法竞赛的c++编程(20)函数的递归
  • OpenLayers:封装Tooltip
  • stm32—ADC和DAC
  • Linux操作系统故障应急场景及对应排查方法
  • 湖北理元理律师事务所:债务优化中的民生保障实践
  • FreeRTOS任务之深入篇
  • 关键字--sizeof
  • Python抽象基类实战:构建广告轮播框架ADAM的核心逻辑
  • robot_lab train的整体逻辑
  • SDC命令详解:使用set_propagated_clock命令进行约束
  • 如何思考?分析篇
  • 深入剖析MySQL锁机制,多事务并发场景锁竞争
  • 34 C 语言字符串转数值函数详解:strtol、strtoll、strtoul、strtoull(含 errno 处理、ERANGE 错误)
  • 硬盘寻址全解析:从 CHS 三维迷宫到 LBA 线性王国
  • Linux安全机制:从SELinux到Intel SGX的堡垒
  • 有什么做外贸的好网站/重庆seo网络推广关键词
  • 门户网站建设和管理情况/阿里指数查询官网
  • js做各类图表网站/北京疫情太严重了
  • 仙居做网站公司/百度竞价培训
  • wap网站的开发/滨州网站建设
  • 网站建设和源代码问题/百度24小时客服电话136