题目大意:
求最小的代价使得序列变成不减或者不增序列 。
题解:
状态:
dp[i][j]表示前i个序列,且最大值为j的代价。
状态转移方程:
dp[i][j]=abs(j-w[i])+min(dp[i-1][k])(k<=j)
注意我们求min(dp[i-1][k]的时候不需要再开一个循环求,因为min都是在该位置的左上部分,那么我们就可以开一个临时遍历MIN用来记录前i-1个序列且最大值小于j的最小代价,每次枚举的是否维护一下该值就行了。
还有一个问题,因为我们第一维枚举的是i,而第二维就不能简单的枚举j了,因为j是0<=j<1e9.但是观察到总共最多有n个数,那么我们就可以考虑简单的离散化一下。
代码实现:
#pragma GCC optimize(2) #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #include<cstdio> #include<cstdlib> #include<vector> #include<map> #include<set> #include<stack> #include<queue> #define PI atan(1.0)*4 #define E 2.718281828 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pb push_back #define debug printf("ac\n"); using namespace std; inline int read() { int a=0,b=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') b=-1; c=getchar(); } while(c>='0'&&c<='9') { a=(a<<3)+(a<<1)+c-'0'; c=getchar(); } return a*b; } const int INF = 0x3f3f3f3f; const int N = 2e3+7; int a[N],b[N]; ll dp[N][N]; int main(){ int n=read(); rp(i,1,n) a[i]=read(),b[i]=a[i]; sort(b+1,b+1+n); rp(i,1,n){ ll MIN=dp[i-1][1]; rp(j,1,n){ MIN=min(MIN,dp[i-1][j]); dp[i][j]=abs(a[i]-b[j])+MIN; } } ll min1=*min_element(dp[n]+1,dp[n]+1+n); reverse(a+1,a+1+n); memcpy(b,a,sizeof(a)); sort(b+1,b+1+n); mst(dp,0); rp(i,1,n){ ll MIN=dp[i-1][1]; rp(j,1,n){ MIN=min(MIN,dp[i-1][j]); dp[i][j]=abs(a[i]-b[j])+MIN; } } ll min2=*min_element(dp[n]+1,dp[n]+1+n); printf("%lld\n",min(min1,min2)); return 0; } /* 7 1 3 2 4 5 3 9 3 7 9 3 5 4 2 3 1 */