(2016年中国大学生程序设计竞赛(杭州)-重现赛) Car 二分 (解决精度问题)

Car
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0

Problem Description
Ruins is driving a car to participating in a programming contest. As on a very tight schedule, he will drive the car without any slow down, so the speed of the car is non-decrease real number.

Of course, his speeding caught the attention of the traffic police. Police record N positions of Ruins without time mark, the only thing they know is every position is recorded at an integer time point and Ruins started at 0.

Now they want to know the minimum time that Ruins used to pass the last position.

Input
First line contains an integer T, which indicates the number of test cases.

Every test case begins with an integers N, which is the number of the recorded positions.

The second line contains N numbers a1, a2, ⋯, aN, indicating the recorded positions.

Limits
1≤T≤100
1≤N≤105
0< ai≤109
ai< ai+1

Output
For every test case, you should output ‘Case #x: y’, where x indicates the case number and counts from 1 and y is the minimum time.

Sample Input
1
3
6 11 21

Sample Output
Case #1: 4

题意:
Ruins 的速度是非递减的,每次警察都是在某一整秒的时间记录Ruins 的位置。问从0开始最少需要多少秒到达最后记录的位置。

分析:
记每两个记录之间的距离为b[i],那么从后往前处理,用sp记录当前的最大速度,为了使时间最短,当b[i]<=sp 我们用一秒开过,当b[i] > sp 时 我们用 t=b[i]/sp +1秒开过,并且最佳的状态是匀速开过,所以sp = b[i]/t;

思路是对的,但是由于题目说的是实数,所以我用先整除在乘的方法判断是否是倍数的处理方法因为精度可能会出问题,而一直WA。。。。

所以最后直接换成了用二分来查找均分的段数。
表示要多打代码啊。。和会长同事想都相同的思路,结果会长一遍过,我WA了。。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100010;
double a[maxn],b[maxn];

int main()
{
    int t,n,kase=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lf",&a[i]);
        a[0] = 0;
        for(int i=n;i>=1;i--)
            b[i] = a[i]-a[i-1];
        double sp = b[n];
        int ans = 1;
        for(int i=n-1;i>=1;i--)
        {
            if(b[i] <= sp)
            {
                ans++;
                sp = b[i];
            }
            else
            {
                int l=1,r=b[i]+1,mid;
                while(l<=r)
                {
                    mid = (l+r)/2;
                    if(b[i]/mid>sp) l = mid+1;
                    else r=mid-1;
                }
                ans += l;
                sp = b[i]/l;
            }
        }
        printf("Case #%d: %d\n",kase++,ans);
    }

    return 0;
}

附上之前思路的代码;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 100010;
double a[maxn],b[maxn];

int main()
{
    int t,n,kase=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lf",&a[i]);
        a[0] = 0;
        for(int i=n;i>=1;i--)
            b[i] = a[i]-a[i-1];
        double sp = b[n];
        int ans = 1;
        for(int i=n-1;i>=1;i--)
        {
            if(b[i] <= sp)
            {
                ans++;
                sp = b[i];
            }
            else
            {
                int t = b[i]/sp;//精度有问题,到后面无法满足t*sp == b[i],导致一直都要多分一份
                if(t*sp == b[i])
                {
                    ans += t;
                    sp = b[i]/(t*1.0);
                }
                else
                {
                    t++;
                    ans += t;
                    sp = b[i]/(t*1.0);
                }
            }
        }
        printf("Case #%d: %d\n",kase++,ans);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值