【POJ1064】二分

嗯,二分的题,我是看了Titanium的题解之后做的。

二分长度,我一开始是把最短的那一个的长度当做上界,1为下界来二分的,而且还是用总长度直接除二分的值来和k比较【对,我就是傻】然后样例输出2.31,我就急了,它有的可以不全都取,而且还不能长于它,这怎么分啊?

认真阅读了一下题解之后,发现上界要设成最长的那个的长度,因为有的太短但是我们可以不选它(k较小)从而得到更优的解。而且是用每一个的长度除二分的值,得到的值累加起来与k比较,这样就满足了题意。

我们把累加起来的值m与k比较,若m < k到左半区间二分,若m > k到右边区间二分,但如果m == k就能停止了吗?或者m != k就只能输出无解了吗?不能!要去右半区间继续二分,一是存在m == k不满足条件,但m > k满足条件的情况,二是要看看说不定会有更大的解。

因为这道题一开始的输入和输出都是保留两位小数的,所以我们可以*100把它化成整数来二分,就避免了精度的问题。

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>

const int MAXN = 1e4 + 5;

int n, k;
int a[MAXN];
int tot;

bool check(int x)
{
    int m = 0;
    for (int i = 0; i < n; i++)
    {
        m += a[i] / x;
    }

    if (m < k) return false;
    else return true;
}

int main()
{
    scanf("%d %d", &n, &k);

    int r = -INT_MAX;
    double sum;
    for (int i = 0; i < n; i++)
    {
        double t;
        scanf("%lf", &t);
        sum += t;
        a[i] = t * 100;
        if (a[i] > r) r = a[i];
    }

    //printf("%d %lf\n", r, sum);

    if (sum < k * 0.01)
    {
        printf("0.00\n");
        return 0;
    }
    tot = sum * 100;

    int l = 1;
    //r = r + 1;
    int max = -INT_MAX;
    //bool flag = false;
    while (l <= r)
    {
        // if (flag == true) break;
        // if (l == r) flag = true;
        //printf("%d %d !\n", l, r);
        int mid = l + (r - l) / 2;
        if (check(mid))
        {
            max = std::max(max, mid);
            l = mid + 1;
        }
        else r = mid - 1;
        //if (l == r) break;
    }

    double ans = (double)max / 100;
    printf("%.2f\n", ans);
    return 0;
}

这里循环边界是l <= r,然后l = mid + 1r = mid - 1。我一开始写的是r = mid,死循环,因为如果l == r,mid = l = r,它就会一直循环下去。但是l < r的话就会出错。这里可以插flag,如果是第二次l == r就退出循环,或者就是r = mid - 1

最后的ans = max / 100要强制转换一下,因为max是int,它/100的值也还是int,不会因为ans是double就自己变成double。

二分。。。大概是会了吧。。。。自己想题都想不出来。。。这道题很裸了。。。。我再去做几道二分的题!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值