http://tioj.ck.tp.edu.tw/problems/1884
這題應該是IOI 2015 Day1裡最簡單的。
用一些DP技巧就可以解出來。
題目給你一個環,編號從0到L-1,L-1後面循環到0,還有n個隊伍,每個隊伍可能在0到L-1之間的任何一個位置。
現在你要發禮物,你一次可以拿K個(小於等於隊伍數量n),在環上移動一格需要1秒,你發完後要再回到0拿k個繼續發,問你最後發完全部人再會到0的最少時間是多少。
觀察一下,可以確定,你最多只需要繞一整圈一次,其他時候你都可以只走左半邊或右半邊來發完禮物,(你發完左邊的禮物後如果手上還有代表你已經發完左邊了,然後你才會去發右邊,如果你還沒發完,那你乾脆發完然後從左邊回去會比較快)。所以我們先看看所有的隊伍在的位置(題目已經幫你排好序),把他分成兩堆,一堆在圓環左半邊,一堆是右半邊,兩堆可能不一樣大喔。
設兩個陣列L[i]、R[j],代表從0開始到左、右半邊的第i、j個隊伍,所需要的最少發禮物時間。
DP轉移式就是:
L[i] = L[i-k] + P[i] * 2,其中P[i]是那一隊到0的最短距離,當i-k小於0的時候L[i-k]都是0,右邊一樣,就不寫了。
然後,我們要考慮兩種狀況,一種是我只在左邊和右邊發完禮物就好了,一種是我最後一次繞一圈比較快。
所以答案就是L[n_l] + R[n_r] 和對於 i 從 0 到 k 取 min(L[n_l-i] + R[n_r-k+i]) + l,這兩個中比較小的那個就是答案。其中 n_l、n_r 是兩邊的隊伍數量,l 是一圈的長度,後面那個的意思就是留下中間的k個隊伍然後最後一次繞一圈發完。
這題還有一點比較有趣的是,因為輸入太大了,輸入優化效果很好,而且這次用了一個新的輸入優化,就是自訂一個函數readchar(),然後用fread一次吃一堆bytes進來,先用陣列存起來,再一次傳一個回去,這樣可以快4秒。
1 |
|