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

点击打开链接

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

时间: 2024-10-25 03:25:32

CodeForces 13C. Sequence 滚动数组+离散化的相关文章

Codeforces 13C Sequence --DP+离散化

题意:给出一个 n (1 <= n <= 5000)个数的序列 .每个操作可以把 n 个数中的某一个加1 或 减 1.问使这个序列变成非递减的操作数最少是多少 解法:定义dp[i][j]为将前i个数变为以j为结尾的非递减序列的最少操作次数. 则有: dp[i][j] = min(dp[i][j], min(dp[i][k]) + Cost(原来第i个位置上的数转换到j))  (1 <= k <= j) 即前i个数以j结尾的状态可以由前i-1个数以小于等于j的k结尾的状态转移过来,取

Codeforces 13C Sequence dp

题目链接:http://codeforces.com/problemset/problem/13/C 题意: 给定n长的序列 每次操作能够给每一个数++或-- 问最少须要几步操作使得序列变为非递减序列 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.

Codeforces 1061C (DP+滚动数组)

题面 传送门 分析 考虑DP 设\(dp[i][j]\)表示前i个数选出的序列长度为j的方案数 状态转移方程为: \[ dp[i][j]= \begin{cases}dp\left[ i-1\right] \left[ j-1\right] +dp\left[ i-1\right] \left[ j-1\right] ,j \equiv 0 (\mod i) \\ dp\left[ i-1\right] \left[ j-1\right],otherwise \end{cases} \] 如果二

hdu 1864 实数离散化+动态规划+滚动数组

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <stack> #include <set> #include <map> #include <vector> using namespace st

Codeforces 712 D. Memory and Scores (DP+滚动数组+前缀和优化)

题目链接:http://codeforces.com/contest/712/problem/D A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A比B大的情况有多少种. dpA[i][j]表示第i轮获得j分的情况数.因为第i轮只和第i-1轮有关,所以这里i用滚动数组优化. 要是普通做法3个for就会超时,所以要用前缀和优化,dpA[i][j]可以由一段连续的dp[i - 1][x]转移过来,所以用sumA数组存取dp[i - 1][x]的前缀

Codeforces 626F Group Projects(滚动数组+差分dp)

F. Group Projects time limit per test:2 seconds memory limit per test:256 megabytes input:standard input output:standard output There are n students in a class working on group projects. The students will divide into groups (some students may be in g

vijos 1002过河[单调dp,滚动数组,离散化]

这道题是NOIP第一道DP优化题,看似容易,实际上想要满分也颇有难度. 传送门:1002 过河 算法 此题显然要用到DP,DP方程也显而易见: if (stone[i]) f[i]=min{f[i-j]}+1; (S<=j<=T) else f[i]=min{f[i-j]}; 这样的时间复杂度为 O(LT) ,空间复杂度为 O(L) . 而此题的L高达 10亿 ,所以这种朴素的方法只能得 30分 ,显然无法AC. 优化 1.滚动数组 根据我们得出的DP方程,状态转移只需用到 f[i-T]~f[

【动态规划】【滚动数组】Educational Codeforces Round 26 D. Round Subset

给你n个数,让你任选K个,使得它们乘起来以后结尾的0最多. 将每个数的因子2和因子5的数量求出来,记作a[i]和b[i]. 答案就是max{ min{Σa[i],Σb[i]} }(a[i],b[i]是选择的那些数). 暴力dp是f(i,j,k)表示前i个数,选j个,其中包含k个5的情况下,最多能包含多少个2. 转移是f(i,j,k)=max{ {f(t,j-1,k-b[i]}+a[i]}(1<=i<t) , f(i-1,j,k) },时间是O(18 * n^3),但空间存不下. 注意第二维为j

!CodeForces 543A Writing Code --DP--(三维dp,滚动数组)

题意:n个程序员一起写m行代码,第i个程序员每写一行有a[i]个bug,求总bug不超过b的分配方案有多少种 分析:这题很像完全背包,不过求的不是最大/最小bug数,求的是bug数小于上限的分配方案.所以这题要用三维dp dp[i][j][k]表示前i个个程序员总共写了j行代码产生了k个bug时的plan数,这题有两种转移:1)第i个程序员再写一行:2)换第i+1号程序员写 所以方程:dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k-a[i]],注意:程序员可能一行都