把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【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=\lfloor\frac dc\rfloor+1\)
  • \(a<b\)时,我们对所有数取倒数,得到\(\frac dc<\frac qp<\frac ba\),递归做即可。
  • \(a\ge b\)时,我们只保留\(\frac ab\)的小数部分,令\(t=\lfloor\frac ab\rfloor\),得到\(\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\n",x,y);
	return 0;
}
posted @ 2020-06-03 18:45  TheLostWeak  阅读(208)  评论(0编辑  收藏  举报