POJ-3232 Accelerator

37 篇文章 0 订阅
20 篇文章 0 订阅
Accelerator
Time Limit: 4000MS Memory Limit: 65536K
   

Description

Shiming (alpc02) is a boy likes to play PopKart very much. He is a good rider in this game. And one day he thought that he became a team leader of a team of N Kart riders.

Today, after the game begins, the riders of his team are now at different places at the racetrack, for that some of the riders got some short cut.

However, we know actually how long has each rider left to run along, and they will ride actually one meter per one time unit (maybe 10ms).

Luckily, Shiming now gets M accelerators, the accelerator can help one rider to ride k meters per one time unit. And all the accelerators are as the same. But one rider can't use more than one accelerator at one time unit.

Shiming is the team leader, and he wants all the team members to finish in the minimal time not just the fastest one to finish the race. He will distribute all the accelerators to the riders.

Note: Here some rules are not as the same as the game we played. At a time unit, Shiming distributes the accelerators to riders for one rider one accelerator, and at the next time unit, all the accelerator can be reused, and Shiming can re-distributes all the accelerators to riders also for one rider one accelerator and the distribution is no relationship with the last time unit.

So you will program to help Shiming to get the actually minimal time the team will use to finish the race.

Input

The input file has T (1<T<20) test cases, and the first line of the file will show the T.

Each of test cases, will be the N (1<= N <= 100000) rider, and N numbers Ai (1<= Ai <= 10^8) show how long will the rider have to finish the race. And the M and the K (1<= K*M <=10^8) for the accelerators.

Output

For each of test cases print a single integer on a single line, the minimal possible number of time units required to finish the race all team.

Sample Input

2
3
2 3 9
1 5
3
2 3 6
1 5

Sample Output

3
2

Source

————————————————————努力的分割线————————————————————
思路:二分答案加大难度咯!。。。不会做Orz。。。搜了一下答案,发现神牛思路。刻骨铭心!
类比一下之前做过的POJ3104-Drying。这道题目相当于多个吹风机!
问题的焦点,就在于多个吹风机可以同时工作。但是假如从“同时”的角度考虑的话,思维复杂度很高。m个加速器,需要我们每一次同时给最大的两个距离加速吗??每一分钟排序一次?行不通的!看一下数据,铁定不能模拟每一分钟。既然不能模拟每一分钟的话……其实不需要给最大的加速!不会做就是因为想太多,没有理解二分答案这种思想的精髓。精髓就是,答案是已知量!!!
之前在做Drying的时候,用cnt累加每个需要使用吹风机的衣服使用吹风机的次数,次数就是分钟……
我们仍然可以再累加“需要使用加速器的次数”然后跟“总次数”作比较!因为就算加速器是多个同时工作的,但有一个共同点,就是每分钟所有加速器都在工作。并不需要你考虑什么每次给最大的距离加速,才能达到最优……我们对答案进行二分,每一次已知量都是死的。当答案是已知量,就可以知道谁需要用加速器,谁不需要。
我们把当前二分的答案对应的总加速次数(一个加速器加速1分钟算作1次)先算好,在枚举的同时从cnt = 0开始进行累加,需要加速几次,就给他几次。注意了!这里需要小心。每次一个车手只能用一个加速器,假如直接就累加需要的次数,可能会出现多个加速器的同时给他加速了。所以给出的次数不能超过二分出的答案。加判断。if (需要加速次数 > 当前二分答案) return false;之后再放心地累加一下,看看有没有超过总次数。
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
int rider, dis[100005], acc, k;
bool check(int m) { //注意!dis[i]非常大,再乘以acc,会int溢出的
    long long tot = (long long)acc * m; //一定要注意!int溢出是随时都可能发生的,所以先强制转换,保存起来
    long long cnt = 0;
    for(int i = 0; i < rider; i++) {
        if(dis[i] <= m) continue;
        else { //dis[i] <= m的话该车手自己就可以跑到终点
            int tmp = (dis[i]-m)/(k-1) + ((dis[i]-m)%(k-1)!=0);//tmp就是当前车手需要的加速次数,向上取整(强制转换有些耗时,不用ceil了吧)
            if(tmp > m) return false; //注意!!这说明即使他一直在加速,一个加速器都无法满足该车手
            cnt += tmp;
            if(cnt > tot) return false;//一旦超过总加速次数,说明次数不够
        }
    }
    return true;
}
int main() {
    int cas;
    scanf("%d", &cas);
    while(cas--) {
        int maxi = 0;
        scanf("%d", &rider);
        for(int i = 0; i < rider; i++){
            scanf("%d", dis+i);
            if(dis[i] > maxi) maxi = dis[i];
        }
        scanf("%d%d", &acc, &k);
        if(k > 1) {
            int l = 1, r = maxi, mid;
            while(l <= r) {
                mid = (l+r) >> 1;
                if(!check(mid)) l = mid + 1; //注意!当check失败的时候,意味着需要更大的答案
                else            r = mid - 1;
            }
            printf("%d\n", l);
        }
        else    printf("%d\n", maxi);
    }
	return 0;
}

有学长说这个神牛的思路用了一个很好的贪心。意即尽可能多得使用加速器。毕竟所有的加速器一直在工作!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值