做题笔记,CF 4.16Div2 C CF1529C The Sports Festival(贪心+DP)

做题笔记,CF 4.16Div2 C CF1529C The Sports Festival(贪心+DP)

题目大意

给你一个序列,你可以对其任意排列。
要求,从1到n,每个位置取之前所有位置上值的最大值-最小值,使总和最小
( n < = 2000 , a [ i ] < = 1 e 9 ) (n<=2000,a[i]<=1e9) (n<=2000,a[i]<=1e9)

做法

我当时的直觉:结论应该是,至少应该长得像“把中间的尽可能排前面,把最大最小的丢后面”,因为一但最大的最小的在前面出现了,那他们显然会一直引入在答案中计算,而直接放最后只会算一次。
所以,初步的思路是把最大的或者最小的扔到后面
那么这个思想放在1个区间的元素更新上,我们不出意外也是把最后一个放成最大的或者最小的,那么如果我们用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示从i到j这个区间的最优值,它必然从两种状态更新得到
即:
把最大的放在最后或者把最小的放在最后
如果我们的 a [ i ] a[i] a[i]是有序的(我们可以排个序),那自然比上步多的代价就是最大值-最小值
d p [ i ] [ j ] = m i n ( d p [ i ] [ j − 1 ] , d p [ i + 1 ] [ j ] ) + a [ j ] − a [ i ] ; dp[i][j]=min(dp[i][j-1],dp[i+1][j])+a[j]-a[i]; dp[i][j]=min(dp[i][j1],dp[i+1][j])+a[j]a[i];
那就是区间DP咯
其实不难,那天晚上一定是太困了,脑子僵硬了没想到逆推
也可能就是菜,不太会dp

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
ll dp[2005][2005];
int n;
int a[2005];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	for(int k=1;k<=n;k++){
		for(int l=1;l<=n;l++){
			int r=l+k-1;
			if(r>n) continue;
			dp[l][r]=min(dp[l][r-1],dp[l+1][r])+a[r]-a[l];
		}
	}
	printf("%lld",dp[1][n]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值