CodeForces - 713C(经典DP)

CodeForces - 713C(经典DP)

题意:给出一个长度为n的数列(n<=3000),每次操作可以把其中一个数增大1或者减小1,求最少操作次数使得数列严格单调递增。
思路:
1.首先如果是变成一个非递减的序列,该怎么做?我们很明显可以发现:最后这个非递减的序列一定只是原来序列排序之后的结果。假设dp[i][j]表示当前枚举到第i个数,让它变成第j大的数需要的最小花费,那么转移方程很显然就是:
dp[i][j]=min(dp[i-1][k]+abs(a[i]-b[j]),dp[i][j]);
复杂度O(n * n * n),考虑一下优化dp[i-1][k]只是上一层的最小值,我们转移的时候记录一下最小值就行。

2.怎么把严格递增序列变成非严格递增序列呢?
a[i]<a[i+1] —> a[i]<=a[i+1]-1 —>a[i]-i<=a[i+1]-(i+1);
很神奇

/*
▄███████▀▀▀▀▀▀███████▄
░▐████▀▒▒▒▒▒▒▒▒▒▒▀██████▄
░███▀▒▒▒ACCEPTED▒▒▒▒▀█████
░▐██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░▐█▌▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████▌
░░█▒▄▀▀▀▀▀▄▒▒▄▀▀▀▀▀▄▒▐███▌
░░░▐░░░▄▄░░▌▐░░░▄▄░░▌▐███▌
░▄▀▌░░░▀▀░░▌▐░░░▀▀░░▌▒▀▒█▌
░▌▒▀▄░░░░▄▀▒▒▀▄░░░▄▀▒▒▄▀▒▌
░▀▄▐▒▀▀▀▀▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒█
░░░▀▌▒▄██▄▄▄▄████▄▒▒▒▒█▀
░░░░▄██████████████▒▒▐▌
░░░▀███▀▀████▀█████▀▒▌
░░░░░▌▒▒▒▄▒▒▒▄▒▒▒▒▒▒▐
░░░░░▌▒▒▒▒▀▀▀▒▒▒▒▒▒▒▐

*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e3+5;
const int M=2e5+5;
const ll INF=1e18;
ll n,dp[N][N],pre[N],a[N],b[N];
int main() {
    
    
    cin>>n;
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    for(int i=1; i<=n; i++) {
    
    
        a[i]=a[i]-i;
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    for(int i=0; i<=n; i++)pre[i]=INF;
    for(int i=1; i<=n; i++) {
    
    
        for(int j=1; j<=n; j++) {
    
    
               if(i==1)dp[i][j]=abs(a[i]-b[j]);
               else dp[i][j]=pre[j]+abs(a[i]-b[j]);
               pre[j]=min(pre[j-1],dp[i][j]);
        }
    }
    cout<<pre[n]<<endl;
}

猜你喜欢

转载自blog.csdn.net/qq_43653111/article/details/106259627