Description
给出正整数 k k ,求离曲线和曲线 g(x)=kx g ( x ) = k x 的交点横坐标最近的分母不超过 105 10 5 的最简有理数
Input
第一行一整数 T T 表示用例组数,每组用例输入一整数 (1≤T≤105,1≤k≤105) ( 1 ≤ T ≤ 10 5 , 1 ≤ k ≤ 10 5 )
Output
对于每组用例,输出离交点横坐标最近的分母不超过 105 10 5 的最简有理数
Sample Input
5
1
2
3
4
5
Sample Output
1/1
153008/96389
50623/24337
96389/38252
226164/77347
Solution
若 ba<dc b a < d c ,则 ba<b+da+c<dc b a < b + d a + c < d c ,其中 ba,dc b a , d c 是最简分数表示
令 k=k2 k = k 2 ,则问题转化为求离 k13 k 1 3 最近的分母不超过 105 10 5 的最简分数,求出 x x 满足,若 x3=k x 3 = k 则答案为 x1 x 1 ,否则令 a=c=1,b=x−1,d=x a = c = 1 , b = x − 1 , d = x ,根据上面的结论对这两个分数二分即可,且注意到以此初值下得到的分数都是最简的,因为 x x <script type="math/tex" id="MathJax-Element-20">x</script>前面的系数总是整除分母,但后面减掉的值总非负且小于分母
Code
#include<cstdio>
using namespace std;
typedef long long ll;
typedef long double ld;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ld Abs(ld x)
{
return x>0?x:-x;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll x,k;
scanf("%I64d",&k);
k=k*k;
x=1;
while(x*x*x<k)x++;
if(x*x*x==k)printf("%I64d/1\n",x);
else
{
ll a=1,b=x-1,c=1,d=x,p,q;
ld tar=k,ans=x*x*x-tar;
while(1)
{
ll e=a+c,f=b+d;
if(e>1e5)break;
ld temp=(ld)f*f*f/e/e/e;
if(Abs(temp-tar)<ans)
{
ans=Abs(temp-k);
p=e,q=f;
}
if(temp>tar)c=e,d=f;
else a=e,b=f;
}
printf("%I64d/%I64d\n",q,p);
}
}
return 0;
}