P2426 删数

题目描述

有N个不同的正整数数x1, x2, ... xN 排成一排,我们可以从左边或右边去掉连续的i(1≤i≤n)个数(只能从两边删除数),剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。

每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。 问如何操作可以得到最大值,求操作的最大价值。

输入输出格式

输入格式:

 

第一行为一个正整数N;

第二行有N个用空格隔开的N个不同的正整数。

 

输出格式:

 

一行,包含一个正整数,为操作的最大值

 

输入输出样例

输入样例#1: 复制
6
54 29 196 21 133 118
输出样例#1: 复制
768

说明

【样例说明】

说明,经过3 次操作可以得到最大值,第一次去掉前面3个数54、29、196,操作价值为426。第二次操作是在剩下的三个数(21 133 118)中去掉最后一个数118,操作价值为118。第三次操作去掉剩下的2个数21和133 ,操作价值为224。操作总价值为426+118+224=768。

【数据规模】

3≤N≤100,N个操作数为1..1000 之间的整数。

 

区间dp啦,

我们设f[i][j]表示删除i到j元素当前所能获得的最大价值,

那么f[i][i]每次只删掉一个元素题目中已明确给出此时可获得最大价值为这个数的值,所以f[i][i]等于它本身。

然后我们初始化一下f[i][j],,序列中每个f[i][j]都初始化为abs(f[j]-f[i])*(j-i+1),这样就得到了一个初始化的,非最优的价值,

(为什么我感觉只有相邻两个,,的值,,,才真正有用,,,,

然后正式枚举区间取最优,

前两层是枚举左右端点,

重点理解第三层,可以这么想:

假如初始i,j位置:

那么枚举k从i到j,

我们已知删除i到j的价值,但删除i到j还可以分着来,

从2一直删到7,我们可以先删2-3,再删4-7,也可以先删2-4,再删5-7……

这样可能答案会更优。

代码: 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

int n;
int f[102][102];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",&f[i][i]);
	for(int i=1;i<n;++i)
		for(int j=i+1;j<=n;++j)
			f[i][j]=abs(f[j][j]-f[i][i])*(j-i+1);
	for(int i=1;i<=n;++i)
		for(int j=i;j<=n;++j)
			for(int k=i;k<j;++k)
				f[i][j]=max(f[i][k]+f[k+1][j],f[i][j]);
	printf("%d",f[1][n]);
	return 0;
}  

如果你不开心,那我就把右边这个帅傻子分享给你吧,  

你看,他这么好看,那么深情的望着你,你还伤心吗?  

真的!这照片盯上他五秒钟就想笑了。  

一切都会过去的。     

原文地址:https://www.cnblogs.com/Mary-Sue/p/9755644.html