10403: D.山區修路

Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 69  Solved: 23 [Submit][Status][Web Board]

Description

某山區的孩子們上學必須經過一條凹凸不平的土路,每當下雨天,孩子們非常艱難。現在村裡走出來的Dr. Kong決定募捐資金重新修建著條路。由於資金有限,為了降低成本,對修好後的路面高度只能做到單調上升或單調下降。

為了便於修路,我們將整個土路分成了N段,每段路面的高度分別A1,A2,….,An。由於將每一段路墊高或挖低一個單位的花費成本相同,修路的總費用與路面的高低成正比。

現在Dr. Kong希望找到一個恰好含N個元素的不上升或不下降序列B1,B2,….,Bn,作為修過的路路段的高度。要求:

| A1-B1| + | A2–B2| + ... + | An-Bn|------>最小

Input

第一行: K                            表示有多少組測試資料。

接下來對每組測試資料:

第1行:       N                表示整個土路分成了N段

第2~N+1行: A1  A2 ……AN     表示每段路面的高度

2≤k≤10      0≤Ai≤10    0≤N≤500    (i=1,…, N)

所有資料都是整數。 資料之間有一個空格。

資料保證| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值不會超過109

Output

對於每組測試資料,輸出佔一行:| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值。

Sample Input

2
7
1 3 2 4 5 3 9
5
8 6 5 6 2

Sample Output

3
1

HINT

 

Source

第七屆河南省賽

題解:把一串序列變為一段連續不增,或者連續不減的最小花費;

dp思想;dp[i][j]代表第i個元素換為第j個值的最小花費;

可列出狀態轉移方程:dp[i][j]=abs(m[i]-n[j])+mn;mn為轉化為1~j間的最小花費;

由於是單調遞增或者單調遞減,只需要升序降序下n陣列就可以了,對了,n陣列是離散化後的陣列;單增或者單減;

程式碼:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
#define SI(x) scanf("%d",&x)
#define SL(x) scanf("%lld",&x)
#define PI(x) printf("%d",x)
#define PL(x) printf("%lld",x)
#define P_ printf(" ")
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
typedef long long LL;
const int MAXN=510;
int m[MAXN],n[MAXN];
int dp[MAXN][MAXN];
int N;
int cmp(int a,int b){
return a>b;
}
int solve(){
int mn;
for(int j=1;j<=N;j++)dp[1][j]=abs(m[1]-n[j]);
for(int i=2;i<=N;i++){
mn=INF;
for(int j=1;j<=N;j++){
mn=min(mn,dp[i-1][j]);
dp[i][j]=abs(m[i]-n[j])+mn;
}
}
int ans=INF;
for(int i=1;i<=N;i++){
ans=min(ans,dp[N][i]);
}
return ans;
}
int main(){
int T;
SI(T);
while(T--){
SI(N);
for(int i=1;i<=N;i++)SI(m[i]),n[i]=m[i];
int ans1,ans2;
sort(n+1,n+N+1);
ans1=solve();
sort(n+1,n+N+1,cmp);
ans2=solve();
printf("%d\n",min(ans1,ans2));
}
return 0;
}

 有大神用左偏樹,劃分樹寫的。。。。

連結:http://blog.163.com/hacker_james/blog/static/659024432011711105241183/

人家的思路:

2.左偏樹(leftist) O(nlogn)
左偏樹作為一種可並堆在這裡可以起到作用
我們將每來一個點,把它單獨建一棵左偏樹,然後跟前一區間的左偏樹中的所存的中位數比較,若小於,則和前一區間的左偏樹合併,知道比前一區間所記錄的中位數是小於或等於當前區間的中位數。
怎樣用左偏樹記錄中位數? 很簡單,每棵左偏樹只儲存(n+1)/2 個元素,則樹頂所儲存的最大值即為中位數
 
注意的是,用左偏樹來求中位數在某些情況下是錯誤的。按照HYH大神的做法,假設現在對於兩個序列 4 5 6 7 8 9 和 1 2 3,合併後其中位數是5。然而,按照左偏樹只存(n+1)/2 個元素的方法,前者只保留 4 5 6, 後者保留 1 2,兩者合併後保留5個元素,所得到的中位數卻是6..
但這道題卻沒影響,至於為什麼? 沒想明白.....
 
3.劃分樹

O(nlogn)
既然要求中位數,而且數列又是靜態數列,可以想到用劃分樹來求.劃分樹除了空間比左偏樹大一點之外,執行效率和正確率都比左偏樹要好。左偏樹的常數相對比較大。