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

题意:

戳这里

分析:

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

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

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

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

分类讨论:

  1. \(a=0\) 时 \(\frac{p}{q}\le \frac{c}{d}\to q\ge \frac{dp}{c}\), 即 \(min_q=\lfloor\frac{d}{c}\rfloor+1\)
  2. \(a\ge b\) 时 把整数部分消掉 \(\frac{a\mod 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\n",min(q,b));
	 	}
	}

}

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

上一篇:QT的QPair类的使用


下一篇:STL—map/multimap容器