[ABC328G] Cut and Reorder 题解

[ABC328G] Cut and Reorder 题解

题目不难,思维难度尚可。

首先需要发现的性质是 1 操作的次数最多只需要使用一次,使用多少次其实都是等价的。

n22 显然考虑状压 dp。平凡的想法是设 dpi,j 表示填数的状态为 i,最后一个填的是 j 位置的数的最小代价。这样的转移复杂度是 O(2nn2) 的,时间和空间上都难以接受。

考虑优化 j 维度。对于每个 i,我们枚举 j 之后由于其转移的特殊性,直接从 [j,n] 依次转移即可。

代码:

#include <bits/stdc++.h>
#define N 22
#define int long long
using namespace std;
int n;
int a[N], b[N];
int c;
int dp[(1 << N) + 5];
vector<int>v[N];
signed main() {
	cin >> n >> c;
	for (int i = 0; i < n; i++)
		scanf("%lld", &a[i]);
	for (int i = 0; i < n; i++)
		scanf("%lld", &b[i]);
	memset(dp, 0x3f, sizeof dp);
	dp[0] = 0;
	for (int i = 0; i < (1 << n) - 1; i++) {
		int cnt = 0, x = i;
		while (x) {
			cnt += (x & 1);
			x >>= 1;
		}
		v[cnt].push_back(i);
	}
	for (int nb = 0; nb < n; nb++)
		for (auto sta : v[nb]) {
			for (int i = 0; i < n; i++)
				if (!((sta >> i) & 1)) {
					int stb = sta, sum = 0;
					for (int j = 0; j < min(n - i, n - nb); j++) {
						int x = i + j;
						if ((sta >> x) & 1)
							break;
						stb |= (1 << x);
						sum += abs(a[nb + j] - b[x]);
						if (sta)
							dp[stb] = min(dp[stb], dp[sta] + sum + c); 
						else
							dp[stb] = min(dp[stb], dp[sta] + sum); 
					}
				}
		}
	cout << dp[(1 << n) - 1] << "\n";
	return 0;
}
posted @   长安19路  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示