The 2015 China Collegiate Programming Contest Game Rooms

Game Rooms

Time Limit: 4000/4000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit Status

Your company has just constructed a new skyscraper, but you just noticed a terrible problem: there is only space to put one game room on each floor! The game rooms have not been furnished yet, so you can still decide which ones should be for table tennis and which ones should be for pool. There must be at least one game room of each type in the building.

Luckily, you know who will work where in this building (everyone has picked out offices). You know that there will be Ti table tennis players and Pi pool players on each floor. Our goal is to minimize the sum of distances for each employee to their nearest game room. The distance is the difference in floor numbers: 0 if an employee is on the same floor as a game room of their desired type, 1 if the nearest game room of the desired type is exactly one floor above or below the employee, and so on.

Input

The first line of the input gives the number of test cases, T(1T100). T test cases follow. Each test case begins with one line with an integer N(2N4000), the number of floors in the building. N lines follow, each consists of 2 integers, Ti and Pi(1Ti,Pi109), the number of table tennis and pool players on the ith floor. The lines are given in increasing order of floor number, starting with floor 1 and going upward.

Output

For each test case, output one line containing Case #x: y, where x is the test case number (starting from 1) and y is the minimal sum of distances.

Sample input and output

Sample InputSample Output
1
2
10 5
4 3
Case #1: 9

Hint

In the first case, you can build a table tennis game room on the first floor and a pool game room on the second floor. In this case, the 5 pool players on the first floor will need to go one floor up, and the 4table tennis players on the second floor will need to go one floor down. So the total distance is 9.

Source

The 2015 China Collegiate Programming Contest
 
题解报告:
其实这是一道比较简单的dp题,关键是转移比较烦人
 不妨有dp(i,j,k)表示修筑的第k种颜色的房屋从j到现在.
转移的时候前一半贪心转移,后一半用cnt进行维护.
具体自己想想,这个解释比较困难。。。
 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 4000 + 50;
long long dp[2][maxn][2] , cnt[2][maxn][2] , sum[maxn][2];
int val[maxn][2] , cur , n ;

void updata(long long & x , long long v){
    if(x==-1) x = v;
    else x = min( x , v );
}

int main(int argc,char *argv[]){
    int Case;
    scanf("%d",&Case);
    for(int cas = 1 ; cas <= Case ; ++ cas){
        cur = 0 ; memset(dp[cur] , -1 , sizeof(dp[cur])) ; memset(cnt[cur] , 0 ,sizeof(cnt[cur]));
        scanf("%d",&n);
        for(int i = 1 ; i <= n ; ++ i){
            scanf("%d%d",&val[i][0] , &val[i][1]);
            for(int j = 0 ; j < 2 ; ++ j) sum[i][j] = sum[i-1][j]+1LL*val[i][j];
        }
        cnt[cur][1][1] = val[1][1] , cnt[cur][1][0] = val[1][0] , dp[cur][1][0] = dp[cur][1][1] = 0;
        for(int i = 2 ; i <= n ; ++ i){
            int pre = cur ; cur ^= 1 ; memset(dp[cur] , -1 , sizeof(dp[cur])); memset(cnt[cur] , 0 ,sizeof(cnt[cur]));
            for(int j = 0 ; j < 2 ; ++ j) cnt[cur][i][j]=val[i][j];
            for(int j = 1 ; j < i ; ++ j)
                for(int k = 0 ; k < 2 ; ++ k){
                    cnt[cur][j][k] = cnt[pre][j][k] + sum[i][k] - sum[j-1][k];
                    if(~dp[pre][j][k]){
                        if(j==1){
                            updata( dp[cur][j][k],dp[pre][j][k]);
                            updata( dp[cur][i][k^1] , dp[pre][j][k] + cnt[pre][1][k^1] + val[i][k]);
                        }
                        else{
                            long long extra = 0;
                            if(((i+j)&1)==0) extra = val[(i+j)>>1][k^1]*1LL*(((i-j)>>1)+1);
                            updata( dp[cur][j][k] , dp[pre][j][k] + extra);
                            updata( dp[cur][i][k^1] , dp[pre][j][k] + cnt[pre][(i+j+1)>>1][k^1] + val[i][k]);
                        }
                    }
                }
            }
        long long ans = min( dp[cur][n][0] , dp[cur][n][1]);
        for(int i = 2 ; i < n ; ++ i)
        {
            for(int k = 0 ; k < 2 ; ++ k){
                long long add = 0;
                int end = (n + i + 2) >> 1;
                for(int j = n ; j >= end ; -- j){
                    add += val[j][k^1] * 1LL* (j - i + 1);
                }
                ans = min( ans , dp[cur][i][k] + add); 
            }
        }
        printf("Case #%d: %lld\n",cas,ans);
     }
    return 0;
}

 

 
 

转载于:https://www.cnblogs.com/Xiper/p/4919234.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值