题目链接:
C. Sonya and Problem Wihtout a Legend
5 seconds
256 megabytes
standard input
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.
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).
Print the minimum number of operation required to make the array strictly increasing.
7
2 1 5 11 5 9 11
9
5
5 4 3 2 1
12 题意: 把这个序列变成严格的单调递增序列,每+1或者-1都花费1,最小花费是多少; 思路: 严格单调递增的变成非严格的可以a[i]-i;然后就是转移了;
dp[i][j]表示第i个数变成j可以满足题目要求的最小花费,现在dp[i][j]=min(dp[i-1][k])+abs(a[i]-j);
j的范围太大,可以排序离散化,用j表示第j个数,那么dp[i][j]=min(dp[i-1][k])+abs(a[i]-b[j]);
这样转移的时间复杂度是O(n*n*n)的,所以还要优化,还可以发现dp[i][j]的转移方程中min(d[i-1][k])是上一层的前缀最小值;
所以可以用一个数组保存下来,复杂度就降为O(n*n)了; AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bits/stdc++.h>
#include <stack>
#include <map> using namespace std; #define For(i,j,n) for(int i=j;i<=n;i++)
#define mst(ss,b) memset(ss,b,sizeof(ss)); typedef long long LL; template<class T> void read(T&num) {
char CH; bool F=false;
for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
F && (num=-num);
}
int stk[70], tp;
template<class T> inline void print(T p) {
if(!p) { puts("0"); return; }
while(p) stk[++ tp] = p%10, p/=10;
while(tp) putchar(stk[tp--] + '0');
putchar('\n');
} const int mod=1e9+7;
const double PI=acos(-1.0);
const LL inf=1e18;
const int N=(1<<20)+10;
const int maxn=3e3+110;
const double eps=1e-12; int n,a[maxn],b[maxn];
LL dp[maxn][maxn],f[maxn];
int main()
{
read(n);
For(i,1,n)
{
read(a[i]);
a[i]=a[i]-i;
b[i]=a[i];
}
sort(b+1,b+n+1);
For(i,0,n)f[i]=inf;
For(i,1,n)
{
For(j,1,n)
{
if(i==1)dp[i][j]=abs(a[i]-b[j]);
else dp[i][j]=f[j]+abs(a[i]-b[j]);
f[j]=min(f[j-1],dp[i][j]);
}
}
cout<<f[n]<<endl;
return 0;
}