【BZOJ2187】fraction(类欧几里得算法)

点此看题面

大致题意: 给定两个分数(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;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2187.html