# 删数
## 题目描述
有N个不同的正整数数x1, x2, ... xN 排成一排,我们可以从左边或右边去掉连续的i(1≤i≤n)个数(只能从两边删除数),剩下N-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|xi – xk|\*(k-i+1),如果只去掉一个数,操作价值为这个数的值。
问如何操作可以得到最大值,求操作的最大价值。
## 输入格式
第一行为一个正整数N;
第二行有N个用空格隔开的N个不同的正整数。
## 输出格式
一行,包含一个正整数,为操作的最大值
## 样例 #1
### 样例输入 #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。
题目中,从左或从右删掉连续的k个数,从左向右删等同于从右先左删,这里就看作从左向右删。
dp[i] 表示含义:删掉前i个数所得到最大。
转移方程式:dp[i] = Max(dp[i],dp[i-1]+sum(j,i));
时间复杂度O()
public static int lineDP(int n){
for(int i = 1;i <= n;i++){
dp[i] = dp[i-1]+num[i];//初始化为,前一段的删掉的最大值加上当前位置上的数
for(int j = i-1;j >= 1;j--)//向前枚举断点
dp[i] = Math.max(dp[i],dp[j-1]+sum(j,i));//dp[i] = Max(dp[i],max[1,j-1]+sum(j,i))转移方程式
}
return dp[n];
}
第二种方法:
区间DP
首先定义dp数组含义:
dp[i][j] 表示含义:从i删到j这个区间所得到的最大值
转移方程式:dp[i][j] = Max(dp[i][j],dp[i][k]+dp[k+1][j])
k为区间[i,j]的断点。
时间复杂度O()
public static int sectionDP(int n){
for(int len = 2;len <= n;len++)//枚举区间长度
for(int l = 1;l+len-1 <= n;l++){
int r = l+len-1;
f[l][r] = sum(l,r);//不分开删
for(int k = l;k < r;k++) {//k 不能等于 l+1,如k = l+1,那么[l,l],[l+1,r]这步操作将会没有
f[l][r] = Math.max(f[l][r],f[l][k]+f[k+1][r]);//分开删
}
}
return f[1][n];
}
sum函数:
public static int sum(int l,int r){
return Math.abs(num[l]-num[r])*(r-l+1);//操作价值为|xi – xk|*(k-i+1)
}