BZOJ 2712. [Violet 2]棒球 类欧几里得

题意:

戳这里

分析:

  • 前置芝士:类欧几里得算法

其实类欧,除了复杂度证明和欧几里得差不多,其他半毛钱关系都没有,类欧是一种合并降低复杂度的方法

首先小数化分数,上界是小数部分 ( imes 10+14) 下界是小数部分 ( imes 10-5)

(frac{a}{b}le frac{p}{q}le frac{c}{d})

分类讨论:

  1. (a=0)(frac{p}{q}le frac{c}{d} o qge frac{dp}{c}), 即 (min_q=lfloorfrac{d}{c} floor+1)
  2. (age b) 时 把整数部分消掉 (frac{amod b}{b}le frac{p-frac{a}{b}*q}{q}le frac{c-frac{a}{b}*d}{d}),这样递归下去边界就是 (a==0)
  3. (a<b) 时 通过翻转一下,转化成第二种情况以倒数继续递归 (frac{b}{a}ge frac{p}{q}ge frac{d}{c})

代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define lc rt<<1
#define rc rt<<1|1
#define pb push_back
#define fir first
#define sec second
#define inl inline
#define reg register

using namespace std;

namespace zzc
{
	typedef long long ll;
	inline ll read()
	{
		int x=0,f=1;char ch=getchar();
		while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
		while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
		return x*f;
	}
	
	ll n,r;
	
	void solve(ll a,ll b,ll c,ll d,ll &p,ll &q)
	{
		if((a/b+1)<=((c-1)/d)) p=(a/b)+1,q=1;
		else if(!a) p=1,q=(d/c)+1;
		else if(a<b) solve(d,c,b,a,q,p);
		else
		{
			solve(a%b,b,c-(a/b)*d,d,p,q);
			p+=q*(a/b);
		}
	}
	
	void work()
	{
		ll a,b,c,d,p,q,x,g;
		while (scanf("%lld 0.%lld",&n,&r)==2)
		{
		    if (r==0) {puts("1");continue;}
		    x=10;while(n--)x*=10;
		    a=r*10-5;b=x;
			c=r*10+5;d=x;
		    g=__gcd(a,b);a/=g;b/=g;
		    g=__gcd(c,d);c/=g;d/=g;
		    solve(a,b,c,d,p,q);
		    printf("%lld
",min(q,b));
	 	}
	}

}

int main()
{
	zzc::work();
	return 0;
}

原文地址:https://www.cnblogs.com/youth518/p/14296191.html