CodeForces 13C. Sequence 滚动数组+离散化

本文介绍了一种算法,用于解决给定一系列整数后,通过最少次数的加1或减1操作,使得序列变为非递减的问题。采用动态规划方法,并通过离散化减少状态数量。

C. Sequence
time limit per test
1 second
memory limit per test
64 megabytes
input
standard input
output
standard output

Little Petya likes to play very much. And most of all he likes to play the following game:

He is given a sequence of N integer numbers. At each step it is allowed to increase the value of any number by 1 or to decrease it by 1. The goal of the game is to make the sequence non-decreasing with the smallest number of steps. Petya is not good at math, so he asks for your help.

The sequence a is called non-decreasing if a1 ≤ a2 ≤ ... ≤ aN holds, where N is the length of the sequence.

Input

The first line of the input contains single integer N (1 ≤ N ≤ 5000) — the length of the initial sequence. The following N lines contain one integer each — elements of the sequence. These numbers do not exceed 109 by absolute value.

Output

Output one integer — minimum number of steps required to achieve the goal.

Sample test(s)
input
5
3 2 -1 2 11
output
4
input
5
2 1 1 1 1
output
1

给你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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值