题意:要在r个同心圆上插n支蜡烛,第i层插k^i支蜡烛,中心可插可不插,要使k*r最小,k*r相同的情况要使r最小。
根据数据范围判断出r最多就40左右,因此枚举r,二分判断k就行。难点在于二分的姿势,因为这题如果二分上界取的大的话k^i会爆long long,在判断k^i是否大于n的时候要写成tmp > (n / mid)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
const ll INF = 0x3f3f3f3f;
ll n;
int main()
{
// cout << INF << endl;
// cout << log(1e12 * 0.5 + 1) / log(2) << endl;
while (scanf("%lld", &n) != EOF)
{
ll ans_r = 1, ans_k = n - 1;
ll min_rk = 50 * (n + 1);
for (int r = 2; r <= 45; r++)
{
ll low = 2, high = n;
while (low <= high)
{
ll mid = (low + high) >> 1;
ll sum = 0;
ll tmp = 1;
for (int i = 1; i <= r; i++)
{
if (tmp > (n / mid))
{
sum = n + 1;
break;
}
tmp *= mid;
sum += tmp;
if (sum > n)
{
sum = n + 1;
break;
}
}
if (sum == n || sum + 1 == n)
{
// if (mid * r == ans_r * ans_k && r < ans_r)
if (mid * r == min_rk && r < ans_r)
{
ans_r = r;
ans_k = mid;
}
// else if (mid * r < ans_k * ans_r)
else if (mid * r < min_rk)
{
min_rk = mid * r;
ans_k = mid;
ans_r = r;
}
break;
}
if (sum > n) high = mid - 1;
else low = mid + 1;
}
}
printf("%lld %lld\n", ans_r, ans_k);
}
return 0;
}