大致题意: 给定两个分数(frac ab)和(frac cd),求(frac pq)满足(frac ab<frac pq<frac cd),且在(q)尽量小的前提下(p)尽量小。
前言
这是怎么想到类欧几里得算法的。。。
我这种蒟蒻只会第一种情况,第二种情况都没想到。
类欧几里得算法
- 当(frac ab)和(frac cd)之间存在整数时,必然选择其中最小的整数。
- 当(a=0)时,条件就只有(frac pq<frac cd),也就是(q>frac{dp}c)。显然(p=1)时(q)可以取到最小值,此时(q=lfloorfrac dc floor+1)。
- 当(a<b)时,我们对所有数取倒数,得到(frac dc<frac qp<frac ba),递归做即可。
- 当(age b)时,我们只保留(frac ab)的小数部分,令(t=lfloorfrac ab floor),得到(frac{a\%b}b<frac{p-qt}q<frac{c-dt}d),同样递归做即可。
于是这道题就做完了,理解起来其实并不难,但也太难想到了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define swap(x,y) (x^=y^=x^=y)
using namespace std;
int a,b,c,d;
I void Get(CI a,CI b,CI c,CI d,int& x,int& y)//类欧几里得算法
{
if(a/b+1<=(c-1)/d) return (void)(x=a/b+1,y=1);if(!a) return (void)(x=1,y=d/c+1);//存在整数;a=0
a<b?(Get(d,c,b,a,x,y),swap(x,y)):(Get(a%b,b,c-(a/b)*d,d,x,y),x+=y*(a/b));//a<b;a≥b(注意修改得到正确的x,y)
}
int main()
{
RI x,y;W(scanf("%d%d%d%d",&a,&b,&c,&d)==4) Get(a,b,c,d,x,y),printf("%d/%d
",x,y);
return 0;
}