$POJ3666\ Making\ the\ Grade$

洛谷

 

$Description$

农夫约翰想改造一条路,原来的路的每一段海拔是$Ai$,修理后是$Bi$,花费$|Ai – Bi|$。我们要求修好的路是单调不升或者单调不降的。求最小花费。

 

$Solution$

首先只讨论数列不降的情况

结论:$B$中的数一定都是$A$中的数

这里可以用数学归纳法证明

证明: 若n=1,显然b[1]=a[1]时最优

假设n-1时结论成立,那么n时:

当a[n]>=b[n-1]时,显然令b[n]=a[n]最优

当a[n]<b[n-1]时,由于数列不降,令b[n]=b[n-1]最优

  这时产生的贡献是b[n-1]-a[n],假设b[n]>b[n-1],则产生贡献更大,没有b[n]=b[n-1]优

最后由数学归纳法可知,原命题成立

有这个结论就好做多啦

另设一个数组$C$表示数组$A$从小到大排序并且离散化后的序列

$f[i][j]$表示将$A1...Ai$变成$B1..Bj$这些数的最小代价

转移:

$f[i][j]=min(f[i-1][1...j])+abs(Ai-Bj)$

这里的$min(f[i-1][1...j])$也是在循环中记录更新即可

 

数列不升的情况:只要把$B$数组重新排列一下,也就是从大到小排列然后再做一遍上面的转移就可以啦

 

$Code$

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define Rg register
 5 #define il inline
 6 #define db double
 7 #define ll long long
 8 #define go(i,a,b) for(Rg int i=a;i<=b;i++)
 9 #define yes(i,a,b) for(Rg int i=a;i>=b;i--)
10 #define inf 1e40
11 using namespace std;
12 il int read()
13 {
14     int x=0,y=1;char c=getchar();
15     while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
16     while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+c-'0';c=getchar();}
17     return x*y;
18 }
19 const int N=2001;
20 int m,n,a[N],b[N],c[N];
21 ll f[N][N],ans=inf;
22 il bool cmp(int x,int y){return x>y;}
23 il void sol()
24 {
25     go(i,1,n)f[1][i]=abs(b[i]-a[1]);
26     go(i,2,n)
27     {
28         ll t=inf;
29         go(j,1,m)
30         {
31             t=min(t,f[i-1][j]);
32             f[i][j]=t+abs(a[i]-b[j]);
33         }
34     }
35     go(j,1,m)if(f[n][j]<ans)ans=f[n][j];
36 }
37 int main()
38 {
39     n=read();go(i,1,n)a[i]=c[i]=read();
40     sort(c+1,c+n+1);
41     go(i,1,n)if(c[i]!=b[m]||i==1)b[++m]=c[i];
42     sol();
43     sort(b+1,b+m+1,cmp);sol();
44     printf("%lld\n",ans);
45     return 0;
46 }
View Code

 

posted @ 2019-05-18 16:08  DTTTTTTT  阅读(219)  评论(0编辑  收藏  举报