HDU 5550 - Game Rooms(DP + 前缀和预处理)

链接:

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 }

 

posted @ 2018-10-14 00:31  Ctfes  阅读(345)  评论(0编辑  收藏  举报