题面:
A given coefficient
K
leads an intersection of two curves
f(x)
and
gK(x)
. In the first quadrant, the curve
f
is a monotone increasing function that
f(x)=x√
. The curve
g
is decreasing and
g(x)=K/x
.
To calculate the x -coordinate of the only intersection in the first quadrant is the following question. For accuracy, we need the nearest rational number to x and its denominator should not be larger than 100000 .
To calculate the x -coordinate of the only intersection in the first quadrant is the following question. For accuracy, we need the nearest rational number to x and its denominator should not be larger than 100000 .
思维过程:本质求最接近x(x*x*x=k*k)的分母小于等于100000的有理数是显然的。
在考虑解法前我们需要先思考一些引理。
引理一:
我们思考一个操作,初态从(1,1)开始,每操作一次将相邻的数求和放在两数之间(比如从(1,1)到(1,2,1))。那么除1以外,其他数x都能在有限操作下使得奇数出现x-1次,偶数出现x-2次。
证明:
我们知道2=1+1,3=1+2或2+1,4=1+3,3+1,我们用归纳法,并且加强命题为对于每个除1以外的其他数都出现在如上分解的两个数中,且组合是唯一的(所以出现了x-1次或x-2次)。假设当n<=k时命题成立,我们证明对于k+1也是成立的,只要证明有且仅有一个相邻数构成的数对(a,k+1-a)。不妨设a>(k+1-a),则因为a<k+1即a<=k,由归纳假设存在且只有一个相邻数构成的数对(2a-k-1,k+1-a)得到a,这就证明了引理。
引理二:
令初态为(0/1,1/1)每次操作为(a/b,c/d)得到(a/b,(a+c)/(b+d),c/d),则给充分多的操作可以跑遍所有的(0,1)区间的有理数。
证明:引理一的推论。
好了可以考虑解法了。
解法:
用上述操作做二分。有上述两个引理做法的可行性是显然的(有序性存在,完备性也有)。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
long double u,v,ans,maxn;
long double ab(long double x){
return x>0?x:-x;
}
int main(){
int t;
cin>>t;
while (t--) {
long long k;
cin>>k;
long long y=1;
while (y*y*y<k*k) {
y=y+1;
}
if (y*y*y==k*k) {
printf("%I64d/1\n",y);
continue;
}
long long x=y-1,mid2;
ans=k*k;
maxn=1e60;
long long l=1,r=1,mid1,a,b;
while (true) {
mid1=l+r;
mid2=x+y;
if (mid1>100000) {
break;
}
u=mid1;
v=mid2;
long double end=v*v*v/u/u/u;
if (ab(end-ans)<maxn) {
maxn=ab(end-ans);
a=mid2;
b=mid1;
}
if (end>ans) {
r=mid1;
y=mid2;
}
else {l=mid1;x=mid2;}
}
printf("%I64d/%I64d\n",a,b);
}
return 0;
}
#include <cstdio>
using namespace std;
long double u,v,ans,maxn;
long double ab(long double x){
return x>0?x:-x;
}
int main(){
int t;
cin>>t;
while (t--) {
long long k;
cin>>k;
long long y=1;
while (y*y*y<k*k) {
y=y+1;
}
if (y*y*y==k*k) {
printf("%I64d/1\n",y);
continue;
}
long long x=y-1,mid2;
ans=k*k;
maxn=1e60;
long long l=1,r=1,mid1,a,b;
while (true) {
mid1=l+r;
mid2=x+y;
if (mid1>100000) {
break;
}
u=mid1;
v=mid2;
long double end=v*v*v/u/u/u;
if (ab(end-ans)<maxn) {
maxn=ab(end-ans);
a=mid2;
b=mid1;
}
if (end>ans) {
r=mid1;
y=mid2;
}
else {l=mid1;x=mid2;}
}
printf("%I64d/%I64d\n",a,b);
}
return 0;
}