题意:
有N个不同的正整数数$x_1, x_2, ... x_n$ 排成一排,我们可以从左边或右边去掉连续的i(1≤i≤n)个数(只能从两边删除数),剩下n-i个数,再把剩下的数按以上操作处理,直到所有的数都被删除为止。
每次操作都有一个操作价值,比如现在要删除从i位置到k位置上的所有的数。操作价值为|x_i–x_k|*(k-i+1),如果只去掉一个数,操作价值为这个数的值。 问如何操作可以得到最大值,求操作的最大价值。
(没看题解A的第一道区间DP)
设f[l][r]表示[l,r]的最优解
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> #include<algorithm> using namespace std; #define int long long #define olinr return #define _ 0 #define love_nmr 0 #define DB double inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-f; ch=getchar(); } while(isdigit(ch)) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } inline void put(int x) { if(x<0) { x=-x; putchar('-'); } if(x>9) put(x/10); putchar(x%10+'0'); } int n; int f[150][150]; inline int abss(int x) { if(x<0) return -x; return x; } signed main() { n=read(); for(int i=1;i<=n;i++) f[i][i]=read(); for(int i=1;i<n;i++) //枚举区间长度 { for(int l=1;l<=n;l++) { int r=l+i; //左右端点 if(r>n)break; for(int k=l;k<=r;k++) //中间点(两个并成一个) { int lft=k==l? f[k][k]:abss(f[k][k]-f[l][l])*(k-l+1); //删左面 int rht=k+1==r? f[k+1][k+1]:abss(f[k+1][k+1]-f[r][r])*(r-k); //删右边 f[l][r]=max(f[l][r],max(f[l][k]+rht,f[k+1][r]+lft)); //左区间答案+当前区间删右边的价值 和 右区间答案+当前区间删左边的价值 取max } } } put(f[1][n]); olinr ~~(0^_^0)+love_nmr; }