【POJ3666】【USACO 2008 Feb Gold】 2.Cow Game 动规

来源:互联网 发布:源码管理工具 编辑:程序博客网 时间:2024/05/04 11:34

题意:有若干个数,然后可以花费i的代价让某个数+i或者-i。

现在要求让你把序列排成不升或者不降,问最小代价。


题解:

首先可以证明,最优花费下最后所有的数都可以是现在的某个数:


证:如果两个数调整后在两个数中间,那么可以把两个数都变为其中一个数,而代价显然是等同的。

这个出来后就好做了。

我们可以先离散化一下,然后f[i][j]表示第i个数变为j时1~i这些数保持非严格单调的最小花费

转移时f[i][j]不必n*n枚举,可以维护一个前缀最优(非常水),然后O(1)转移。


然后做一遍非升,一遍非降出解。


代码:

#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 2500#define inf 0x3f3f3f3f3f3f3f3fllusing namespace std;struct LSH{int x,id;bool operator < (const LSH &a)const{return x<a.x;}}lsh[N];int cnt,n,w[N];long long f[N][N];int main(){//freopen("test.in","r",stdin);int i,j,k;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&lsh[i].x),lsh[i].id=i;sort(lsh+1,lsh+n+1),lsh[0].x=-1;for(i=1;i<=n;i++){if(lsh[i].x!=lsh[i-1].x)lsh[++cnt].x=lsh[i].x;w[lsh[i].id]=cnt;}// 离散化结束,lsh中对应原值//升序for(i=1;i<=n;i++){long long temp=inf;for(j=0;j<=cnt;j++){temp=min(temp,f[i-1][j]);f[i][j]=temp+abs(lsh[w[i]].x-lsh[j].x);}}long long ans1=inf;for(i=0;i<=cnt;i++)ans1=min(ans1,f[n][i]);//降序for(i=1;i<=n;i++){long long temp=inf;for(j=cnt;j>=0;j--){temp=min(temp,f[i-1][j]);f[i][j]=temp+abs(lsh[w[i]].x-lsh[j].x);}}long long ans2=inf;for(i=0;i<=cnt;i++)ans2=min(ans2,f[n][i]);cout<<min(ans1,ans2)<<endl;return 0;}


0 0
原创粉丝点击