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;
}