1. 程式人生 > >HDU 5550 - Game Rooms(DP + 前綴和預處理)

HDU 5550 - Game Rooms(DP + 前綴和預處理)

pro esp \n microsoft -s print ase game type

鏈接:

http://acm.hdu.edu.cn/showproblem.php?pid=5550

題意:

一個大樓有n(2≤n≤4000)層,每層可以建一個乒乓球房或者一個遊泳房,且每種房間在大樓裏至少要有一個。
已知每層有ti個乒乓球運動員和pi個遊泳運動員(1≤ti,pi≤1e9)。
問怎樣建房,才能使得所有運動員到相應房間的總距離最小,輸出最小值。

分析:

因為每種房間在大樓裏至少要有一個,所以肯定會有這樣一種狀態:第i層是一種房間,第i+1層是另一種房間。
所以可以設d[i][x]:第i層是x房間,且第i+1層是另一種房間時,前i層的最優解。
則狀態轉移方程為:d[i][x] = min(d[k][x^1] + 第k+1~i層都是x房間時所產生的最小總距離),1≤k<i。


其中x^1表示另一種房間,求第L~R層都是x房間時所產生的最小總距離可以用前綴和預處理,具體看代碼。
BTW,此題為2015年CCPC的銀牌題。

代碼:

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 typedef long long int LLI;
 6 const LLI INF = 0x3f3f3f3f3f3f3f3f;
 7 const int UP = 4000 + 5;
 8 LLI sum[UP][2]; // sum[i][x]:前i層x運動員的總人數
 9
LLI dist[UP][2]; // dist[i][x]:前i層所有x運動員到第0層的總距離 10 LLI d[UP][2]; // d[i][x]:第i層是x房間,且第i+1層是另一種房間時,前i層的最優解 11 12 LLI toLeft(int L, int R, int x) { // 第L~R層的所有x運動員到第L-1層的總距離 13 return (dist[R][x]-dist[L-1][x]) - (sum[R][x]-sum[L-1][x]) * (L-1); 14 } 15 16 LLI toRight(int L, int R, int x) { // 第L~R層的所有x運動員到第R+1層的總距離
17 return (sum[R][x]-sum[L-1][x]) * (R+1) - (dist[R][x]-dist[L-1][x]); 18 } 19 20 LLI process(int L, int R, int x) { // 第L~R層的所有x運動員到第L-1層或R+1層的總距離最小值 21 int M = L + (R-L)/2; 22 return toLeft(L, M, x) + (M+1>R ? 0 : toRight(M+1, R, x)); 23 } 24 25 int main() { 26 int T, n; 27 LLI t, p; 28 scanf("%d", &T); 29 for(int cases = 1; cases <= T; cases++) { 30 scanf("%d", &n); 31 for(int i = 1; i <= n; i++) { 32 scanf("%lld%lld", &t, &p); 33 sum[i][0] = sum[i-1][0] + t; 34 sum[i][1] = sum[i-1][1] + p; 35 dist[i][0] = dist[i-1][0] + t*i; 36 dist[i][1] = dist[i-1][1] + p*i; 37 } 38 LLI ans = INF; 39 for(int i = 1; i < n; i++) { 40 d[i][0] = toRight(1, i, 1); // 前i層都是0房間,第i+1層是1房間的總距離 41 d[i][1] = toRight(1, i, 0); // 前i層都是1房間,第i+1層是0房間的總距離 42 for(int k = 1; k < i; k++) { 43 d[i][0] = min(d[i][0], d[k][1] + process(k+1,i,1)); // 第k+1~i層都是0房間 44 d[i][1] = min(d[i][1], d[k][0] + process(k+1,i,0)); // 第k+1~i層都是1房間 45 } 46 ans = min(ans, d[i][0] + toLeft(i+1,n,0)); // 後i+1層都是1房間 47 ans = min(ans, d[i][1] + toLeft(i+1,n,1)); // 後i+1層都是0房間 48 } 49 printf("Case #%d: %lld\n", cases, ans); 50 } 51 return 0; 52 }

HDU 5550 - Game Rooms(DP + 前綴和預處理)