1. 程式人生 > >POJ3666 Making the Grade

POJ3666 Making the Grade

class def 16px 最小 %d turn 答案 name 單調遞增

POJ3666 Making the Grade

題意:

給定一個長度為n的序列A,構造一個長度為n的序列B,滿足b非嚴格單調,並且最小化S=∑i=1N |Ai-Bi|,求出這個最小值S,1<=N<=2000,1<=Ai<=1e9.

引理:在滿足S最小化的情況下,一定存在一種構造序列B的方案,使得B中的數值都在A中出現過。

由此,用一個數組b[i]初始化=a[i],然後對b從小到大排序,用f[i][j]表示完成了B中前i個數的構造,第i個數為b[j]時的最小的S.當第i個數等於b[j]時,因為B序列是單調遞增的,所以之前構造的數一定在b[1]~b[j]之間,用tmp維護其最小值即可,則有:

    for(res i=1 ; i<=n ; i++)
    {
        LL tmp=f[i-1][1];
        for(res j=1 ; j<=n ; j++)
        {
            tmp=min(tmp,f[i-1][j]);
            f[i][j]=tmp+abs(a[i]-b[j])
        }
    }

最後答案即為f[1~n]的最小值。

進一步優化:

發現第一維可以省略掉。

完整代碼:

技術分享圖片
 1 #include <cstdio>
 2 #include <iostream>
 3
#include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define INF (2147483640) 8 const int N=4000+100; 9 int a[N],b[N]; 10 int f[N],n; 11 12 int main() 13 { 14 scanf("%d",&n); 15 for(int i=1 ; i<=n ; i++) scanf("%d",&a[i]),b[i]=a[i]; 16 17 sort(b+1
,b+n+1); 18 int ans=INF; 19 for(int i=1 ; i<=n ; i++) 20 { 21 int t=INF; 22 for(int j=1 ; j<=n ; j++) 23 { 24 t=min(t,f[j]); 25 f[j]=abs(b[j]-a[i])+t; 26 } 27 } 28 for(int i=1 ; i<=n ; i++) 29 ans=min(ans,f[i]); 30 printf("%d\n",ans); 31 return 0; 32 } 33
View Code

POJ3666 Making the Grade