【题目】C. Sonya and Problem Wihtout a Legend
【题意】给定n个数字,每次操作可以对一个数字±1,求最少操作次数使数列递增。n<=10^5。
【算法】动态规划+前缀和优化
【题解】★令b[i]=a[i]-i,则a[i]递增等价于b[i]不递减。
这样做之后,显然数字加减只能到b[i]中出现的数字,而不会出现其它数字。
令f[i][j]表示前i个数,第i个数字大小为c[j](第j大的数字)的最少操作次数。
f[i][j]=abs(b[i]-c[j])+min{f[i-1][k]},k<=j
令g[i][j]表示min{f[i][k]},k<=j,则有:
g[i][j]=min{ g[i][j-1],abs(b[i]-c[j])+g[i-1][j] }
初始g[0][i]=0。
复杂度O(n^2)。
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
#define ll long long
#define lowbit(x) x&-x
using namespace std;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a<b?b:a;}
int ab(int x){return x>?x:-x;}
//int MO(int x){return x>=MOD?x-MOD:x;}
//void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
/*------------------------------------------------------------*/
const int inf=0x3f3f3f3f,maxn=; int n,a[maxn],b[maxn];
ll f[maxn][maxn];
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)a[i]=read()-i,b[i]=a[i];
sort(b+,b+n+);
int x=;
for(int i=;i<=n;i++)f[x][i]=;
for(int i=;i<=n;i++){
x=-x;f[x][]=1ll<<;
for(int j=;j<=n;j++)f[x][j]=min(f[x][j-],ab(b[j]-a[i])+f[-x][j]);
}
printf("%lld",f[x][n]);
return ;
}