luogu P1442鐵球落地 題解

2022-08-28 12:39:11 字數 3040 閱讀 1996

n(n≤100000)個平台上空有乙個鐵球,球每次落到某個平台上後,遊戲者可以選擇向左或向右滾,球滾動和落下的速度都是1。由於鐵球的質量不太好,每次落下的高度不能超過max。設計一種策略,使得球盡快落到地面而不被摔碎。假設地面高度為0,且無限寬。

第一行是兩個數n,max。

第二行兩個數,分別表示鐵球起始位置的橫縱座標。

接下來n行,第i行是三個正整數hi,li,ri,

輸入資料保證有解,且平台的高度互不相同、各邊緣與橫座標的值均互不相同。

僅乙個數,為鐵球到達地面的最短時間。

輸入 #1複製

5 3

6 10

5 2 4

9 3 9

6 7 10

2 1 5

3 8 11

這題應該不難想到使用dp求解。

我們先將每塊木板按照高度排序。

然後我們按照從矮到高的順序倒序遍歷這些木板。

可能你會問為什麼要從矮到高的順序dp。

其實從高到到矮的順序dp,其實從高到矮並不是不可以。

但從低到高會來的更方便。

因為從低到高的話,我們只需要考慮從左邊下落到達的木板,和從右邊下落到達的兩個木板繼承就可以了。

然而從高到低我們並不方便找到哪些下落可以到達該木板。

以上都是廢話

假若我們已經求得了這個木板左右下落會到達哪些木板,

我們記 ch[i][1/0] 0表示i的左邊下落到達的木板,1表示右邊下落到達的木板。

dp[i][1/0] 0表示如果下落到左邊木板,最小費時,1表示下落到右邊木板的最小費時。

la[i] 表示 i 的右端點橫座標, ra[i] 表示 i 的左端點橫座標。

a[i].h 記錄 i 木板的高度。

dp 方程如下:

dp[i][0]=min(dp[i][0],dp[ch[i][0]][0]+la[i]-la[ch[i][0]]+a[i].h-a[ch[i][0]].h);dp[i][0]=min(dp[i][0],dp[ch[i][0]][1]+ra[ch[i][0]]-la[i]+a[i].h-a[ch[i][0]].h);dp[i][1]=min(dp[i][1],dp[ch[i][1]][0]+ra[i]-la[ch[i][1]]+a[i].h-a[ch[i][1]].h);dp[i][1]=min(dp[i][1],dp[ch[i][1]][1]+ra[ch[i][1]]-ra[i]+a[i].h-a[ch[i][1]].h);

其實這後面轉移就是路徑的模擬,不難明白。

dp方程解決了,還有乙個問題,那就是如何處理出每個木板左右下落後到達的木板?

乙個比較好理解的方案是線段樹。

這裡使用了區間賦值和單點修改

我們從低到高列舉木板,查詢左/右端點下線段樹上對應的值。

這值就是我們要求的落到的那個木板編號。

當這個木板完後,他就是對應區間(木板的左端點到右端點),最上面的木板了。

它上面的應當會落在它的上面。

於是區間修改。把這段區間的值修改為這個木板的編號。

到此,問題得到完美解決

等等,我們千萬不要忘記離散化,以及dp時特判。

如果當前的木板下落到的木板編號為0,那麼dp是當前木板的高度。

具體看**

#include#include

#include

#include

#define ls k<<1

#define rs k<<1|1typedef

long

long

ll;using

namespace

std;

const

int n=1e6;

ll n,m,cnt;

ll lx[n

<<2],ch[n][2],w[n<<4],tag[n<<4

];//

ll la[n

<<2],ra[n<<2],dp[n][2

];//

struct

node

}a[n];

inline

void read(ll &x)

inline

void

update(ll k,ll x,ll y)

inline

void

change(ll k,ll x,ll y,ll l,ll r,ll val)

ll mid=x+y>>1

;

if(tag[k]) update(k,x,y);//區間賦值的標記下傳

change(ls,x,mid,l,r,val);

change(rs,mid+1

,y,l,r,val);

}inline ll query(ll k,ll x,ll y,ll pos)

intmain()

sort(lx+1,lx+cnt+1

);//離散化陣列排序

sort(a+1,a+1+n);//木板高度排序

for(i=1;i<=n;i++)

for(i=1;i<=n;i++)

memset(dp,

0x3f,sizeof

(dp));

dp[0][0]=dp[0][1]=0

;//顯而易見的初始化

for(i=1;i<=n;i++)

else dp[i][0]=a[i].h;

}if(a[i].h-a[ch[i][1]].h<=m)

else dp[i][1]=a[i].h;}}

printf("%d

",min(dp[n][0],dp[n][1

]));//最後答案為轉移到起始位置 n 的值。

}//剛好99行

14 4 選單功能

選單功能就是與使用者的溝通介面。1 在workermanager.h標頭檔案中新增show menu 成員函式。class workermanager 2 在workermanager.cpp中實現show menu 成員函式。其實這個函式就是在螢幕中把選單介面列印出來,沒什麼技術含量。顯示選單 v...

14 4 執行緒的通訊

執行緒通訊 乙個執行緒完成自己的任務時,就要通知另外乙個執行緒去 例子就是生產者與消費者關係 wait 等待。如果執行緒執行了wait方法,那麼該執行緒會進入等待的狀態 notify 喚醒等待的執行緒 注意 1 wait和notify方法是屬於objeck類的。2 wait和notify方法必須是要...

南陽144 某種序列

時間限制 3000 ms 記憶體限制 65535 kb 難度 4 描述 數列a滿足an an 1 an 2 an 3,n 3 編寫程式,給定a0,a1 和 a2,計算a99 輸入 輸入包含多行資料 每行資料報含3個整數a0,a1,a2 0 a0,a1,a2 100000000 資料以eof結束 輸出...