[ABC232F] Simple Operations on Sequence 题解
我们把问题陈述中的第一个操作称为 "增/减",第二个操作称为 "交换"。
在这里,让我们对问题陈述稍加限制,一旦执行了增/减操作,就不能再执行交换操作。
换句话说,唯一允许的操作过程是:
- 首先执行任意次数(可能为零)的交换;
- 然后执行任意次数(可能为零)的递增/递减。
这一修改不会改变答案。因为 "递增/递减后交换 "可以替换为 "交换后递增/递减"。
从初始状态
要使
-
首先,在 "任意次数交换 "步骤中,将
修改为 需要 次交换,其中 是 的转换数。这需要 日元。 -
接下来,在 "递增/递减任意次数 "步骤中,要使
等于 ,需要 次递增/递减(其中 表示绝对值)。这需要 日元。
因此
.
因此,这个问题可以归结为 "通过选择合适的
这里是
其中
这里要注意,
因此,对于
,
则
因此,原来的问题可以改写如下。
你将按照
的顺序确定 的元素。当第一个 元素 已经确定时,选择 作为下一个元素 的代价是
求确定
中所有元素的最小总成本。
我们将用动态程序设计法(DP)来解决这个问题。
当
当没有确定
对于
(到达状态 所需的最小总成本)
原问题的答案是达到状态
首先,考虑 DP 的初始化。根据
.
另外,为了方便起见,我们将
.
接下来,考虑 DP 的转换。
当当前状态为状态
相应地,对于每个
通过上述初始化和转换计算出
因此,解决这个问题总共需要
C++ 代码:
#include <bits/stdc++.h> using namespace std; using ll = long long; const ll mod = 1e9 + 7; const int N = 200005; const ll INF = 1e18; ll n, X, Y; ll a[N], b[N], f[1 << 18]; int check(int s, int x) { int res = 0; for (int p = 1; p <= n; p++) { if ((s & (1 << (p - 1))) == 0 && p < x) res++; } return res; } int main() { scanf("%lld%lld%lld", &n, &X, &Y); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); for (int i = 1; i <= n; i++) scanf("%lld", &b[i]); for (int i = 1; i < (1 << n); i++) { f[i] = INF; } for (int s = 0; s < (1 << n); s++) { int cnt = 0; for (int i = 1; i <= n; i++) if (s & (1 << (i - 1))) cnt++; for (int x = 1; x <= n; x++) { if (s & (1 << (x - 1))) continue; f[s | (1 << (x - 1))] = min(f[s | (1 << (x - 1))], f[s] + abs(a[x] - b[cnt + 1]) * X + check(s, x) * Y); } } printf("%lld\n", f[(1 << n) - 1]); return 0; }
本文作者:jxy2012的博客
本文链接:https://www.cnblogs.com/jxy2012/p/18132457
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步