[HDOJ 4430] [2012 Asia Changchun Regional Contest K Problem] 解题报告

2012 Asia Changchun Regional Contest

K题 Yukan's Birthday

HDOJ 4430


知识点总结:

  • 二分查找,时间复杂度: log(n)

  • 整数的幂运算不要使用pow()函数,因为无法保证精度问题,通过【快速求幂】方法求解。

    // 快速求幂 原理
    a^n = a^(2*n/2)
    // 快速求幂 时间复杂度
    log(n)
    

解题思路:

这道题是通过枚举+二分的方法解决的。

首先,通过等比数列求和公式我们可以得到r的最大值的范围:r_max < 40, 因此面对[1~40]范围的r可以进行穷举。

接下来, 最外圈的蜡烛个数 k ^ r < n, 所以我们可以进一步缩减k的范围,防止运算结果爆出long long,然后通过二分确定与r对应的k的值。

最后,选取r * k最小的组合即可。


代码:

https://github.com/HouJP/ACM_HDOJ/blob/master/hdoj_4430.cpp

/*************************************************************************
    > File Name: 4430.cpp
    > Author: HouJP
    > Mail: peng_come_on@126.com 
    > Created Time: 五  8/ 8 10:03:50 2014
************************************************************************/
	
#include <cstdio>
#include <cstring>
#include <cmath>

#define LL long long

LL n, k;
int r;

LL fast_pow(LL a, int b) {
	LL exp = 1;
	while (b) {
		if (b & 1) {
			exp *= a;
		}
		a =  a * a;
		b >>= 1;
	}
	return exp;
}

LL binary_find(int r, LL k_max, LL n) {
	LL k_l = 2, k_r = k_max, k_m, sum;
	while (k_l <= k_r) {
		k_m = (k_l + k_r) / 2;
		sum = k_m * ( 1 - fast_pow(k_m, r)) / (1 - _m);
		if (sum == n) {
			return k_m;
		} else if (sum > n) {
			k_r = k_m - 1;
		} else if (sum < n) {
			k_l = k_m + 1;
		}
	}
	return -1;
}

int main() {
	while (~scanf("%lld", &n)) {
		k = n - 1;
		r = 1;
		for (int i = 2; i < 40; ++i) {
			LL kk;
			LL k_max = (LL)pow(n, 1.0 / i);
			kk = binary_find(i, k_max, n);
			if (-1 != kk) {
				if ((i * kk < r * k) || ((i * kk == r * k ) && (i < r))) {
					r = i;
					k = kk;
				}
			}
			kk = binary_find(i, k_max, n - 1);
			if (-1 != kk) {
				if ((i * kk < r * k) || ((i * kk == r * k) && (i < r))) {
					r = i;
					k = kk;
				}
			}
		}
		printf("%d %lld\n", r, k);
	}
	return 0;
}
posted @ 2014-08-09 08:57  HouJP  阅读(139)  评论(1)    收藏  举报