[poj3666]Making the Grade

Making the Grade
(简洁题意请往下翻)

Description

A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).

You are given N integers A1, ... , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . ... , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is

| A B 1| + | A B 2| + ... + | AN -  BN |

Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.

Input

* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single integer elevation: Ai

Output

* Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

Sample Input

7
1
3
2
4
5
3
9

Sample Output

3

Source

USACO 2008 February Gold
 
 
 
题意:
A[i]为输入序列,B[i]为构造序列.
构造非严格单调序列B[i],使sigma | A[i]-B[i] | 最小
 
引理:构造出的B[i]一定在A[i]中出现过.(感性理解一下)
 
[题解]
最开始想到O(n^3)的dp:
f[i]表示B[i]=A[i]时,最小花费.
状态转移方程:
cost(j,i)表示将j~i中一段变成A[j],剩下的变成A[i](连续的)的最小花费,需要O(n)统计
 
然后,这个dp是可以优化的:
将A中数字离散化(并去重),f[i][j]表示B[i]=b[j]时的最小花费(b[j]是哈希数组,从小到大排序,与下面AC代码中的b数组含义相同)
这样可以用minf数组统计出f[i][1],f[i][2]......f[i][j]中的最小值,可以做到O(1)转移
状态转移方程见代码.
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define ll long long
 5 #define maxn 2001
 6 #define mLL 0x7f7f7f7f7f7f7f7f
 7 using namespace std;
 8 int n,num[maxn];
 9 //f[i]为A[i]与B[i]相同时,构成序列1-i的最小花费
10 ll f[maxn],ans1=mLL,ans2=mLL;
11 int cost(int j,int i){//将j+1~i-1区间内的左边一部分数改成A[i],右边一部分改成A[j]
12     int tmp=0;
13     for(int k=j+1;k<i;k++)
14         tmp+=abs(num[k]-num[j]);
15     int ret=tmp;
16     for(int k=i-1;k>j;k--){
17         tmp=tmp-abs(num[k]-num[j])+abs(num[k]-num[i]);
18         ret=min(ret,tmp);
19     }
20     return ret;
21 }
22 void debug(){
23     int a,b;
24     while(scanf("%d%d",&a,&b)!=EOF){
25         printf("%d\n",cost(a,b));
26     }
27     return;
28 }
29 int main(){
30     scanf("%d",&n); 
31     for(int i=1;i<=n;i++)
32         scanf("%d",&num[i]);
33     memset(f,0x7f,sizeof(f));
34     f[1]=0;
35     for(int i=1;i<=n;i++)//B[i]=A[i]
36         for(int j=1;j<i;j++)
37             if(num[j]<=num[i]) f[i]=min(f[i],f[j]+cost(j,i));
38     for(int i=1;i<=n;i++)
39         ans1=min(ans1,f[i]+cost(i,n));
40     memset(f,0x7f,sizeof(f));
41     f[1]=0;
42     for(int i=1;i<=n;i++)
43         for(int j=1;j<i;j++)
44             if(num[j]>=num[i]) f[i]=min(f[i],f[j]+cost(i,j));
45     for(int i=1;i<=n;i++)
46         ans2=min(ans2,f[i]+cost(i,n));
47     printf("%lld\n",min(ans1,ans2));
48     // debug();
49     return 0;
50 }
TLE的O(n^3)算法
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define maxn 2001
 5 #define ll long long
 6 using namespace std;
 7 ll f[maxn][maxn],minf[maxn][maxn],ans=0x7f7f7f7f7f7f7f7f;
 8 int n,m,a[maxn],b[maxn];//b:hash
 9 void dp(){
10     memset(f,0x3f,sizeof(f));
11     memset(minf,0x3f,sizeof(minf));
12     memset(minf[0],0,sizeof(minf[0]));
13     for(int i=1;i<=n;i++){
14         for(int j=1;j<=m;j++){//去重后的数字,从小到大排序
15             f[i][j]=min(f[i][j],minf[i-1][j]+abs(a[i]-b[j]));
16             minf[i][j]=min(minf[i][j-1],f[i][j]);
17         }
18     }
19     ans=min(ans,minf[n][m]);
20 }
21 int main(){
22     scanf("%d",&n);
23     for(int i=1;i<=n;i++)
24         scanf("%d",&a[i]),b[i]=a[i];
25     sort(b+1,b+1+n);
26     m=unique(b+1,b+1+n)-(b+1);
27     dp();
28     for(int i=1;i<=m/2;i++)
29         swap(b[i],b[m-i+1]);
30     dp();
31     printf("%lld\n",ans);
32     return 0;
33 }

猜你喜欢

转载自www.cnblogs.com/al76/p/9497091.html