简略题意:问分母在1e5范围内的最简分数中,距离 y=k/x 和 y=(√x) 的在第一象限的交点的 x 坐标最近的分数是什么。
我们可以先暴力找到最接近k的整数部分,如果直接找到了答案就输出即可。
否则答案即在
x−11和x1
之间,这部分的复杂度是
O(k2/3)
的。
然后考虑如何在这段区间找数。
给出闭区间
[l,r]
,二分找一个数挺显然的,不过为了使得我们二分出的分数是最简分数,我们可以参考法里数列的构造法。
对于
[luld,rurd]
,每次取二分中点
[lu+ruld+rd]
即可保证每次为最简分数。
关于法里数列可以看这里。
#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const long double eps = 1e-8;
//int dcmp(long double x) { if(_abs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;
long double _abs(long double x) {
return x<0?-x:x;
}
namespace solver {
int t;
LL k;
void solve() {
scanf("%d", &t);
LL a1,a2, b1, b2, m1, m2, A, B;
while(t--) {
scanf("%lld", &k);
LL x = 0;
while(x*x*x<k*k) x++;
if(x*x*x==k*k) printf("%lld/1\n", x);
else {
long double tt = k * k;
LL au = x-1, bu = x;
LL ad = 1, bd = 1;
long double minv = 1e60;
for(;;) {
LL mu = au + bu, md = ad + bd;
if(md > 100000) break;
long double u = mu, v = md;
long double val = u*u*u/v/v/v;
if(_abs(val-tt) < minv) {
minv = _abs(val-tt);
A = mu, B = md;
}
if(val > tt) bu = mu, bd = md;
else au = mu, ad = md;
}
printf("%lld/%lld\n", A, B);
}
}
}
}
int main() {
solver::solve();
return 0;
}