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 }