cf 372 div2 E. Sonya and Problem Wihtout a Legend dp

来源:互联网 发布:广发期货软件下载 编辑:程序博客网 时间:2024/06/06 03:32
题目地址:http://codeforces.com/contest/714/problem/E

题意:给一序列,可对这个序列的每个数做加一或减一的操作,问最小的操作数使这个序列变为严格递增序列

思路:看这个博客才明白的:http://blog.csdn.net/miracle_ma/article/details/52537208
首先如果题目要求的序列是非严格递增序列的话,则产生的新序列所含有的数一定可以都是原序列的数。
大致的证明思路:如果一个数要变小,那么这个数只要小到和它右边的数一样大就好了,再小得到的解不会是最优解;如果一个数要变大,那么这个数只要大到和它左边的数一样小就好了,再大得到的解不会是最优解。
试着把原问题转换为非严格递增序列的问题:只要使a[i]-=i就好了

转化为非严格递增后,如何解决,既然每个数都是原序列中的数,用dp[i][j]表示第i个数变为原序列第j大的数需要的成本,则有dp[i][j]=abs(b[i]-a[j])+min(dp[i-1][k]),b[i]指第i个数,a[j]指序列中第j大的数

#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;typedef long long LL;const int MAXN=3000+5;int a[MAXN],b[MAXN];LL maxn[MAXN],dp[MAXN][MAXN];int main(){    int n;    while(~scanf("%d",&n)){        for(int i=0;i<n;++i){            scanf("%d",a+i);            a[i]-=i;            b[i]=a[i];        }        sort(a,a+n);        int sub=unique(a,a+n)-a;        for(int i=0;i<sub;++i){            dp[0][i]=abs(b[0]-a[i]);            if(i==0) maxn[i]=dp[0][i];            else maxn[i]=min(dp[0][i],maxn[i-1]);        }        for(int i=1;i<n;++i){            for(int j=0;j<sub;++j){                dp[i][j]=abs(b[i]-a[j])+maxn[j];                if(j==0) maxn[j]=dp[i][j];                else maxn[j]=min(maxn[j-1],dp[i][j]);            }        }        LL ans=1e18;        for(int i=0;i<sub;++i)            ans=min(ans,dp[n-1][i]);        printf("%I64d\n",ans);    }}


0 0
原创粉丝点击