P1292 倒酒
这个题有很多模型,这个是一个变形。
我令一个解为x
两个整数Pa和Pb,分别表示从体积为a ml的酒杯中倒出酒的次数和将酒倒入体积为b ml的酒杯中的次数(酒杯一开始为空)。
b最后是0,所有倒入b中的都会倒入a中,而每次a倒出都是从满的状态倒出来,所以剩下的x=Pb*b-Pa*a。
因为a和b要互质,所以x一定是gcd(a,b)的整数倍,不然令两边同时除以gcd(a,b),左边就是分数了,而右边要求的Pa和Pb包括a,b都是整数,那就无解了。那x最小就是gcd(a,b)。
然后扩欧求出一组解,转而求最小解。
怎么求呢?
如果Pa和Pb是一组解,那么(Pa+a)*b-(Pb+b)*a=x也成立,显然,
(Pa+a/gcd(a,b))*b-(Pb+b/gcd(a,b))*a=x也成立,而且这是可以调整的最小幅度,即不会错过最优解,可以类似的不断调整使解达到最小或变成正数。
细节问题
-ax+by=gcd(a,b),这里的变量都是正数,在套扩欧时,还是exgcd(a,b,x,y),然后不断调整使x变成负数,然后输出-x,y即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<algorithm> 5 #include<cmath> 6 #include<ctime> 7 #include<set> 8 #include<map> 9 #include<stack> 10 #include<cstring> 11 #define inf 2147483647 12 #define For(i,a,b) for(register int i=a;i<=b;i++) 13 #define p(a) putchar(a) 14 #define g() getchar() 15 //by war 16 //2017.11.6 17 using namespace std; 18 int a,b; 19 int g; 20 int x,y; 21 void in(int &x) 22 { 23 int y=1; 24 char c=g();x=0; 25 while(c<'0'||c>'9') 26 { 27 if(c=='-') 28 y=-1; 29 c=g(); 30 } 31 while(c<='9'&&c>='0')x=(x<<1)+(x<<3)+c-'0',c=g(); 32 x*=y; 33 } 34 void o(int x) 35 { 36 if(x<0) 37 { 38 p('-'); 39 x=-x; 40 } 41 if(x>9)o(x/10); 42 p(x%10+'0'); 43 } 44 45 int exgcd(int a,int b,int &x,int &y) 46 { 47 if(!b) 48 { 49 x=1,y=0; 50 return a; 51 } 52 int t=exgcd(b,a%b,x,y); 53 int temp=x; 54 x=y; 55 y=temp-(a/b)*y; 56 return t; 57 } 58 59 int main() 60 { 61 in(a),in(b); 62 g=exgcd(a,b,x,y); 63 a/=g; 64 b/=g; 65 while(x>0) 66 { 67 x-=b; 68 y+=a; 69 } 70 while(x+b<=0&&y>=a) 71 { 72 x+=b; 73 y-=a; 74 } 75 o(g),p(' '); 76 o(-x),p(' '),o(y); 77 return 0; 78 }