题目描述:
Winy是一家酒吧的老板,他的酒吧提供两种体积的啤酒,aa ml 和 bb ml,分别使用容积为 aa ml 和 bb ml 的酒杯来装载。
酒吧的生意并不好。Winy 发现酒鬼们都非常穷。有时,他们会因为负担不起 aa ml 或者 bb ml 啤酒的消费,而不得不离去。因此,Winy 决定出售第三种体积的啤酒(较小体积的啤酒)。
Winy 只有两种杯子,容积分别为 aa ml 和 bb ml,而且啤酒杯是没有刻度的。他只能通过两种杯子和酒桶间的互相倾倒来得到新的体积的酒。
为了简化倒酒的步骤,Winy 规定:
- a≥ba≥b;
- 酒桶容积无限大,酒桶中酒的体积也是无限大(但远小于桶的容积);
- 只包含三种可能的倒酒操作:
- 将酒桶中的酒倒入容积为 bb ml 的酒杯中;
- 将容积为 aa ml 的酒杯中的酒倒入酒桶;
- 将容积为 bb ml 的酒杯中的酒倒入容积为 aa ml 的酒杯中。
- 每次倒酒必须把杯子倒满或把被倾倒的杯子倒空。
Winy希望通过若干次倾倒得到容积为 aa ml 酒杯中剩下的酒的体积尽可能小,他请求你帮助他设计倾倒的方案。
输入格式:
输入共一行两个整数 aa 和 bb,满足 0<b≤a≤1090<b≤a≤109。
输出格式:
第一行一个整数 cc,表示可以得到的酒的最小体积。
第二行两个整数 PaPa 和 PbPb(中间用一个空格分隔),分别表示从体积为 aa ml 的酒杯中倒出酒的次数和将酒倒入体积为 bb ml 的酒杯中的次数。
若有多种可能的 Pa,PbPa,Pb 满足要求,那么请输出 PaPa 最小的一个。若在 PaPa 最小的情况下,有多个 PbPb 满足要求,请输出 PbPb 最小的一个。
解题过程:
通过找规律得到酒的最小容量为gcd(a,b),但是如果用gcd去模拟,看数据 0<a,b<1*10^9,如果酒杯很小,就会得到TLE的结果。此时转换思路,发现可得公式:a*Pa+b*Pb=gcd(a,b);这是ex_gcd的公式,固本题的思路为ex_gcd;此外还需注意,利用ex_gcd所得到的pa,pb只是一组解,不一定是最小解,所以还要额外求出最小解才能得到正确结果。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int ex_gcd(int a,int b,int &x,int &y){
if(b==0){
x=1;
y=0;
return a;
}
int r=ex_gcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*x;
return r;
}
int main(){
int x,y,a,b;
cin>>a>>b;
int gcd=ex_gcd(a,b,x,y);
cout<<gcd<<endl;
x*=-1;
a*=-1;
while(x<0||y<0){
x+=b/gcd*(x<0);
y-=a/gcd*(x>=0);
}
cout<<x<<" "<<y<<endl;
}