hdu 3666 Making the Grade

题目大意
给出了一列数,要求通过修改某些值,使得最终这列数变成有序的序列,非增或者非减的,求最小的修改量。
分析
首先我们会发现,最终修改后,或者和前一个数字一样,或者和后一个数字一样,这样才能修改量最小。
我们先根据原数列排序,确定元素的大小关系,对应编号为p[i]
dp[i][j] 表示考虑前i个元素,最后元素为序列中 第j小元素的最优解
dp[i][j] = MIN(dp[i-1][k]) + abs(a[i]-a[p[j]]), (0<k<=j)   
刚开始以为是o(n^3)的复杂度,后来想想,k值在每次j循环的时候就能确定最小值
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define INF 100000000000000
 7 #define maxn 2005
 8 using namespace std;
 9 int n;
10 typedef long long LL;
11 LL a[maxn],b[maxn];
12 LL dp[maxn][maxn];
13 int main()
14 {
15     while(scanf("%d",&n)!=EOF)
16     {
17         for(int i=1; i<=n; i++)
18         {
19             scanf("%I64d",&a[i]);
20             b[i]=a[i];
21         }
22         sort(b+1,b+1+n);
23         for(int i=1; i<=n; i++)
24             for(int j=1; j<=n; j++)
25                 dp[i][j]=INF;
26         for(int j=1; j<=n; j++)
27         {
28             dp[1][j]=(a[1]-b[j]);
29             if(dp[1][j]<0)
30                 dp[1][j]=-dp[1][j];
31         }
32 
33         for(int i=2; i<=n; i++)
34         {
35             LL k=dp[i-1][1];
36             for(int j=1; j<=n; j++)
37             {
38                 k=min(dp[i-1][j],k);
39                 LL tem=(a[i]-b[j]);
40                 if(tem<0)
41                     tem=-tem;
42                 dp[i][j]=min(dp[i][j],k+tem);
43                 // printf("==%I64d
",dp[i][j]);
44             }
45         }
46         LL minn=INF;
47         for(int i=1; i<=n; i++)
48             minn=min(minn,dp[n][i]);
49         printf("%I64d
",minn);
50     }
51     return 0;
52 }
原文地址:https://www.cnblogs.com/tsw123/p/4415737.html