《挑战程序设计竞赛》3.1.5 二分搜索-其它 POJ1759 3484

POJ1759

http://poj.org/problem?id=1759

题意

N个灯泡离地Hi,满足H1 = A ,Hi = (Hi-1 + Hi+1)/2 – 1,HN = B ,求满足所有Hi>=0的最小B。

思路

这个题首先要进行一定的数学分析。由递推式可得:

H(i)-H(i-1) = H(i-1)-H(i-2)+2

上式中i从3取到n,等式两边叠加,以及变形后分别得:

H(n)-H(2) = H(n-1)-H(1)+2(n-2)
H(n)-H(n-1) = H(2)-H(1)+2(n-2)

上式中H(n)-H(n-1)也就是第n项与上一项的差值,随n的增大而增大。所以H(n)-H(n-1)为不大于0的最大值时,H(n)达到最小值。
这也确定了二分法的解法:以H(2)-H(1)为目标值,求使H数列最小值不小于0时的目标最小值。
求得了以H(2)-H(1)的最小值,也就确定了B:
H(N) = (n-1)(H(2)-H(1))+(n-1)(n-2)+H(1)
由于B的误差要求是小数点后2位,为了保险起见,二分法求H(2)-H(1)的终止条件是(ub - lb > 1e-7)。

代码

Source Code

Problem: 1759       User: liangrx06
Memory: 240K        Time: 0MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

const int N = 1000;

int main(void)
{
    int n;
    double a, b;

    cin >> n >> a;
    double lb = -N, ub = N;
    while (ub - lb > 1e-7) {
        double mid = (lb + ub) / 2;
        int i = (2-mid/2 < n) ? (2-mid/2) : n;
        i = (i <= 0) ? 1 : i;
        double low = (i-1)*mid + (i-2)*(i-1) + a;
        if (low >= 0) ub = mid;
        else lb = mid;
    }
    b = (n-1)*ub + (n-2)*(n-1) + a;

    printf("%.2lf\n", b);

    return 0;
}

POJ3484

http://poj.org/problem?id=3484

题意

给出N个X Y Z组合,其中X Y Z组合能够输出 X, X + Z, X + 2 * Z… X + K * Z(X+K * Z <= Y)问这些输出的数中,有哪个数是输出奇数次的。数据保证最多只有一个数出现奇数次。

思路

假设J是输出奇数次的那个数,那么小于J的所有输出的数的个数之和就为偶数,大于等于J的所有输出的数的个数之和为奇数。
如果以i为标准,输出小于等于i的所有数之和,i从小到大变化的话,就会有如下的形式:
偶偶偶偶偶偶奇奇奇。。。第一个奇刚好是J
通过上面的规律,就可以通过二分搜索来求得J了。
这个题有两个地方需要注意:
(1)IO跟其它题不一样,我在这上面WA了无数次。。。真坑
(2)注意数据类型用long long

代码

Source Code

Problem: 3484       User: liangrx06
Memory: 1072K       Time: 110MS
Language: C++       Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

typedef long long LL;
struct Node {
    LL x, y, z;
};

vector<Node> vec;
char s[200];

LL check(LL mid)
{
    LL cnt = 0;
    for (int i = 0; i < vec.size(); i ++) {
        LL tmp = min(mid, vec[i].y) - vec[i].x;
        if (tmp >= 0)
            cnt += ((tmp / vec[i].z) + 1);
    }
    return cnt;
}

void solve()
{
    Node t;
    LL lb = INT_MAX, ub = 0;
    t.x = 0;
    sscanf(s, "%lld%lld%lld", &t.x, &t.y, &t.z);
    lb = min(lb, t.x);
    ub = max(ub, t.y);
    vec.push_back(t);
    if (!t.x) return;
    while (gets(s) && s[0]) {
        sscanf(s, "%lld%lld%lld", &t.x, &t.y, &t.z);
        lb = min(lb, t.x);
        ub = max(ub, t.y);
        vec.push_back(t);
    }
    lb --;
    while (ub - lb > 1) {
        LL mid = (lb + ub) / 2;
        if (check(mid) & 1) ub = mid;
        else lb = mid;
    }
    if ((check(ub) & 1) == 0)
        printf("no corruption\n");
    else
        printf("%lld %lld\n", ub, check(ub)-check(ub-1));
    vec.clear();
}

int main(void)
{
    while (gets(s))
        solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值