给你n个数,每次操作都可以使某个数加1或者减1,求至少多少次操作使得这n个数是非递减的。非递减定义:
a1 ≤ a2 ≤ ... ≤ aN
要求最少次数,肯定是由原来的数构成的。
dp[i][j]表示前i个数以a[j]为结尾的满足要求的最少的操作,可是题目给的最大数是10^9,二维数组的j元素不可能开这么大,所以需要离散化一下,改成前i个数以第j个数为结尾的满足要求的最少的操作。
dp[i][j]=min(dp[i][j],第i-1个位置前j个数的最小操作+fabs(b[j]-a[i]) b数组是原来输入的a数组排好序且离散化之后的数组
因为b数组是从小到大排好序的,所以在第i个位置时第j个数肯定比i-1个位置的前j个数要大。
最后dp[5000][5000]也不能存下,那么这个二维数组就要滚一下了。
//780 ms 0 KB
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#define ll __int64
using namespace std;
const ll inf = 1ll<<62;//inf要取很大
ll dp[2][5007],a[5007],b[5007];
ll min(ll x,ll y)
{
return x<y?x:y;
}
int main()
{
ll n;
while(scanf("%I64d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%I64d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
int tot=unique(b+1,b+n+1)-b-1;//离散化
dp[1][1]=inf;
for(int i=1;i<=tot;i++)
{
dp[1&1][i]=fabs(b[i]-a[1]);
dp[2&1][i]=inf;
}
for(int i=2;i<=n;i++)
{
ll minn=inf;
for(int j=1;j<=tot;j++)
{
minn=min(minn,dp[(i-1)&1][j]);//取上一个位置中前j颗不同高度的树中花费最小
dp[i&1][j]=min(dp[i&1][j],minn+fabs(b[j]-a[i]));//当前位置等于上一个位置中前j颗树花费最小+这个位置是第j颗树的花费
}
for(int j=1;j<=tot;j++)dp[(i+1)&1][j]=inf;
}
ll ans=inf;
for(int i=1;i<=tot;i++)ans=min(ans,dp[n&1][i]);//取最后一个位置是第j颗树是花费最小
printf("%I64d\n",ans);
}
return 0;
}
本文介绍了一种算法,用于解决给定一系列整数后,通过最少次数的加1或减1操作,使得序列变为非递减的问题。采用动态规划方法,并通过离散化减少状态数量。
1668

被折叠的 条评论
为什么被折叠?



