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

Codeforces 2153D Not Alone 题解 [ 绿 ] [ 线性 DP ] [ 分类讨论 ]

Not Alone:唐题。

容易将题意转化为:环上的每一个颜色段长度都 \(\ge 2\),求最小操作数。

再考虑一个 \(O(n^2\log n)\) 的暴力,定义 \(dp_i\) 表示以 \(i\) 结尾的最小操作数,然后枚举前一个转移点 \(j\)。继续考虑如何计算 \([j + 1, i]\) 的最小操作数,容易注意到这是个经典的绝对值不等式,于是取中位数即可。

感性地发现一大段相等的数不如拆成几个小段的区间。于是从 \(n = 2, 3,4\) 的情况入手,发现:

  • \(n = 2\) 时,只能全部相等。
  • \(n = 3\) 时,只能全部相等。
  • \(n = 4\) 时,\([a_1, a_2, a_3, a_4]\) 分成 \([a_1, a_2],[a_3, a_4]\) 比直接不分段更优秀,因为分段时的代价就是 \(|a_2 - a_1| + |a_4 - a_3|\),不分段的时候,分类讨论中位数的位置发现最小值才是 \(|a_2 - a_1| + |a_4 - a_3|\),甚至有可能比它更大。因此不分段一定不优。
  • \(n = 5, 6, 7, \cdots\) 时,类似 \(n = 4\),考虑数学归纳法,发现分成若干个长度为 \(2, 3\) 的段一定最优。

于是线性 DP 求解最小方案即可。

拓展到环上,破环为链复杂度会爆炸,所以只需要分类讨论首尾相接处的情况即可。详见代码,时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 400005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n, a[N], ans, res, dp[N];
ll work(int l, int r)
{dp[l - 1] = 0;for(int i = l; i <= r; i++){dp[i] = inf;if(i == l) continue;// 2dp[i] = min(dp[i], dp[i - 2] + abs(a[i] - a[i - 1]));// 3if(i == l + 1) continue;int mx = max(a[i], max(a[i - 1], a[i - 2])), mn = min(a[i], min(a[i - 1], a[i - 2]));int md = (a[i] ^ a[i - 1] ^ a[i - 2] ^ mx ^ mn);dp[i] = min(dp[i], dp[i - 3] + mx - md + md - mn);}return dp[r];
}
void solve()
{cin >> n;ans = inf;for(int i = 1; i <= n; i++)cin >> a[i];// 0 + 0ans = min(ans, work(1, n));// 1 + 1if(n > 3)ans = min(ans, work(2, n - 1) + abs(a[1] - a[n]));// 1 + 2if(n > 4){int mx = max(a[1], max(a[n], a[n - 1])), mn = min(a[1], min(a[n - 1], a[n]));int md = (a[1] ^ a[n - 1] ^ a[n] ^ mx ^ mn);ans = min(ans, work(2, n - 2) + mx - md + md - mn);}// 2 + 1if(n > 4){int mx = max(a[1], max(a[n], a[2])), mn = min(a[1], min(a[2], a[n]));int md = (a[1] ^ a[2] ^ a[n] ^ mx ^ mn);ans = min(ans, work(3, n - 1) + mx - md + md - mn);}cout << ans << "\n";
}
int main()
{//freopen("sample.in", "r", stdin);//freopen("sample.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;cin >> t;while(t--) solve();return 0;
}
http://www.hskmm.com/?act=detail&tid=28352

相关文章:

  • __closure__:闭包的“身份证”
  • Codeforces Round 1057 (Div. 2)
  • “表达式”(Expression)和“语句”(Statement)概念辨析
  • 每日一题 ###121买卖股票的最佳时机
  • 10.10总结
  • LibreChat-图文并茂手把手教你界面配置 | Adorable LibreChat Interface Configuration Guide
  • GAE-广义优势估计算法介绍
  • qemu模拟单片机
  • RAG-检索增强生成
  • “猴子补丁”(monkey patch)跟猴子有关吗?
  • Yapi 使用docker在cenos7上部署教程与基本使用
  • C语言vsC++
  • 20251010 之所思 - 人生如梦
  • 2025.10.10
  • 个人书单-从心流出发,学习积极心理学
  • 等号(=)在C语言和python中有什么区别?
  • AI元人文(十四)之价值共生篇:再论物物交换——作为价值共生基础的元协议
  • 4.布局系统
  • Python clickhouse-driver 类库使用学习总结
  • 虚拟环境QA
  • 计算机系统知识 - 呓语
  • 详解 `a, b = b, a + b`:执行逻辑、常见误区与赋值符号辨析
  • xdown 全能下载
  • 2025.10.10 - 20243867孙堃2405
  • 密码系统设计
  • c#服务安装和卸载等等
  • 进制表示
  • 在AI技术快速实现创意的时代,挖掘用户真实需求成为关键——某知名电池管理工具需求洞察
  • 从梯度提升树到分布式机器学习算法
  • iPhone手机越狱后出现闪退的解决方法