AtCoder Beginner Contest 232 F - Simple Operations on Sequence (状压DP)

题目链接:https://atcoder.jp/contests/abc232/tasks/abc232_f

题目大意
给出两个长度为 n 的序列 A 和 B,有两个操作分为别:

  • 在序列 A 中选择一个元素加一或减一,花费 x
  • 在序列 A 中选择一个元素与其右边的元素交换(不能选择最后一个元素),花费 y

可以执行上述操作任意次,问让序列 A 等于序列B的最小花费

思路
状压DP。
定义: d p x dp_x dpx 表示 x x x 在二进制位下,对应为 1 1 1 的位置 i i i A i A_i Ai 全部安排好的花费。
eg: d p 1 1 10 dp_{11_{10}} dp1110 = d p 101 1 2 dp_{1011_2} dp10112 表示 a 1 、 a 2 a_1、a_2 a1a2 a 4 a_4 a4 放到 b 1 、 b 2 、 b 3 b_1、b_2、b_3 b1b2b3 上的最小花费。

状态转移方程看代码。

ACcode

#include<bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

const int maxn = 1e6 + 5;
const int mod = 998244353;

ll dp[maxn];
ll a[100], b[100];

int main(){
	
	ll n, x, y;
	cin >> n >> x >> y;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 1; i <= n; i++) cin >> b[i];
	
	memset(dp, 0x3f, sizeof(dp));
	dp[0] = 0;
	
	for(int i = 0; i < (1<<n); i++){
		int c = __builtin_popcount(i), d = 0;
		// c 表示前边已经安排好几个a,需要把 a(j+1) 放到 b(c+1) 上
		// d 表示要把 a(j+1) 放到 b(c+1) 的位置上要交换几次
		// 也就是说有 d 个 a 放在了 a(j+1) 前边,需要交换 d 次
		for(int j = n-1; j >= 0; j--){
			if(i>>j&1) d++;
			else dp[i|(1<<j)] = min(dp[i|(1<<j)], dp[i] + d*y + abs(a[j+1]-b[c+1])*x);
		}
	}
	
	cout << dp[(1<<n)-1] << endl;
			
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值