BZOJ 2712. [Violet 2]棒球 类欧几里得
作者:互联网
题意:
分析:
- 前置芝士:类欧几里得算法
其实类欧,除了复杂度证明和欧几里得差不多,其他半毛钱关系都没有,类欧是一种合并降低复杂度的方法
首先小数化分数,上界是小数部分 \(\times 10+14\) 下界是小数部分 \(\times 10-5\)
\(\frac{a}{b}\le \frac{p}{q}\le \frac{c}{d}\)
分类讨论:
- \(a=0\) 时 \(\frac{p}{q}\le \frac{c}{d}\to q\ge \frac{dp}{c}\), 即 \(min_q=\lfloor\frac{d}{c}\rfloor+1\)
- \(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\)
- \(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;
}
标签:2712,le,frac,小数,欧几里得,Violet,pair,define,BZOJ 来源: https://www.cnblogs.com/youth518/p/14296191.html