StkOvflow

STACK OVERFLOW!

一言(ヒトコト)

loj.ac
——lmh

CF13C. Sequence

题目描述

给你一个序列a,要求你把它变成一个递增的序列,将目标序列与这个序列对应位置上所有数的差值和成为修改花费,求最小的修改花费。

解题思路

对于序列上的修改是一眼DP,具体是应该如何去DP

首先我们思考一下,可以得到一个重要性质,就是我们最小花费的目标序列,必定是由原先序列的数字构成的。

推导

因为我们可以将由原先序列的数字加减后成员不变构成的新序列看成是由原先的序列经过一系列的交换操作后得到的,而成员不同的新序列是由原先的序列经过一系列的交换然后再加减得到的,那么我们不做额外的加减操作,花费肯定是比额外的要小的,因此我们只需要从原序列上考虑就行了

所以我们就可以得到我们的DP

状态表示

f[i][j]ij

DP边界

f[0][i]=0

转移方程

我们可以将一个情况分成两类:
1.i个数本来排名就在第i位,可以安插f[i][j]=f[i][j1]
2.i个数和目标序列第i位不同,需要改,所以f[i]][j]=f[i1][j]+abs(c[j]a[i])
以上两种取min即可

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long

using namespace std;

const int N = 5e4 + 10;
int f[2][N], n, a[N], c[N];

signed main() 
{
	scanf("%lld", &n);
	
	for (int i = 1; i <= n; i ++ ) 
		scanf("%lld", &a[i]), c[i] = a[i];
		
	sort(c + 1, c + 1 + n);
	
	memset(f, 0x3f, sizeof f);
	for (int i = 1; i <= n; i ++ ) f[0][i] = 0;
	
	for (int i = 1; i <= n; i ++) 
	{
		for (int j = 1; j <= n; j ++ ) 
			f[1][j] = min(f[1][j - 1], f[0][j] + abs(c[j] - a[i]));
		swap(f[0], f[1]);
	}
	
	int res = 1e18;
	for (int i = 1; i <= n; i ++ ) 
	 	res = min(res, f[0][i]);
	printf("%lld\n", res);
	
	return 0;
}
posted @   StkOvflow  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示