Codeforces 713C C. Sonya and Problem Wihtout a Legend (经典DP)

54 篇文章 0 订阅
42 篇文章 1 订阅


C. Sonya and Problem Wihtout a Legend
time limit per test
5 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Sonya was unable to think of a story for this problem, so here comes the formal description.

You are given the array containing n positive integers. At one turn you can pick any element and increase or decrease it by 1. The goal is the make the array strictly increasing by making the minimum possible number of operations. You are allowed to change elements in any way, they can become negative or equal to 0.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 3000) — the length of the array.

Next line contains n integer ai (1 ≤ ai ≤ 109).

Output

Print the minimum number of operation required to make the array strictly increasing.

Examples
input
7
2 1 5 11 5 9 11
output
9
input
5
5 4 3 2 1
output
12
Note

In the first sample, the array is going to look as follows:

2 3 5 6 7 9 11

|2 - 2| + |1 - 3| + |5 - 5| + |11 - 6| + |5 - 7| + |9 - 9| + |11 - 11| = 9

And for the second sample:

1 2 3 4 5

|5 - 1| + |4 - 2| + |3 - 3| + |2 - 4| + |1 - 5| = 12

这个题跟poj3666是同一个类型只是这个是严格的,那个不必严格的





++
 
 
 
n  
 
x  
 
dp[i][j]=abs(b[i]a[j])+min(dp[i1][k]),kj  
iji1kj  
O(n2)O(1)  
aiajij,ij  
aiiajj  
ai=aii


直接考虑结果的整个数列   必然存在那么几个数  他是从始至终 都没有变过  那么假设有一些数会受到这个数影响 比如一个数ai不变 如果aj 是受ai影响 那么就会消耗  

先考虑这样一个问题,如果是非严格单调递增该如何做,我们会发现每次调整,都是调整某个数字为原先数列中存在的数字,最后才是最优的,所以,我们设DP[i][j]表示前i个数字,最后一个数为原先数列排序后第j大的数字的最小代价,那么做一遍n2的DP就能够获得答案,现在题目中要求的是严格单调递增,那么就用到一种经典的处理方法,a[i]=a[i]-i,这样子就转化为非严格单调的问题了。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 3e3 + 5;
const ll INF = 0x7fffffffffffffff; //这里不是const int 是 const ll
ll a[maxn], b[maxn], dp[maxn][maxn]; //因为每个数都在1e9范围内,所以要用ll
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a[i] -= i;   //这里就是把严格递增转换成非严格递增
        b[i] = a[i];
    }
    sort(b+1, b+n+1);
    for(int i = 1; i <= n; i++)
    {
        ll min1 = INF;   
        for(int j = 1; j <= n; j++)
        {
            min1 = min(min1, dp[i-1][j]);  //这个min1表示的就是i-1个数并且最后一个数小于等于b[j]的最小值,这种记录方式很好
            dp[i][j] = min1 + abs(a[i]-b[j]);
        }
    }
    ll ans = INF;
    for(int j = 1; j <= n; j++)
    {
        ans = min(dp[n][j], ans);  //看哪个结尾最小
    }
    cout << ans << endl;
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值