一遇到数学就卡住,我这是怎么肥4...(或许到图论会愉悦吧,逃)
Description
* 给出两种重量为的 A, B 的砝码,给出一种使用最少的砝码的方
式,称出重量 C。
我们可以比较容易地列出方程$Ax+By=C$.之后来一发exgcd搞,求出方程的一组特解。平时我们求的往往是最小解,但这次它却要求两解之和最小。我们要做特殊的变形。
首先我们应该知道方程的通解:(约定:设x0,y0为一组特解,t为任意整数,设a>b(不行再交换))
那么有 $x=x0+b/gcd*t$
$y=y0-a/gcd*t$
而本题中,我们的答案就是|x|+|y|的最小值。
平时那种加模数再取膜的方法行不通了,我们从数学的角度分析这个函数,x是单调递增,而y是单调递减。因为a>b,所以减的更快。所以我们可以推出,当$y0-a/gcd*t=0$时函数有最小值(具体我也布吉岛啊qwq我好菜)
可得$t=y0*gcd/a$
所以我们把答案约束在了一个范围,即[t-1,t+1],枚举取最值即可。
不过要注意的是,我们开始约定了a>b,当a<b时我们进行了交换,但是输出的时候,我们需要换过来。(错了几次的原因)
Code
1 #include<algorithm> 2 #include<cstdio> 3 4 using namespace std; 5 typedef long long ll; 6 7 ll a,b,c,x,y; 8 9 ll exgcd(ll aa,ll bb,ll &xx,ll &yy) 10 { 11 if(bb==0) 12 { 13 xx=1;yy=0; 14 return aa; 15 } 16 ll d=exgcd(bb,aa%bb,xx,yy); 17 ll z=xx;xx=yy;yy=z-yy*(aa/bb); 18 return d; 19 } 20 21 ll sabs(ll u) 22 { 23 if(u>0) return u; 24 else return -u; 25 } 26 27 int main() 28 { 29 while(scanf("%lld%lld%lld",&a,&b,&c)!=EOF&&a!=0) 30 { 31 x=0,y=0; 32 bool flag=0; 33 if(a<b) swap(a,b),flag=1; 34 ll gong=exgcd(a,b,x,y); 35 x=x*(c/gong);y=y*(c/gong); 36 ll t=y*gong/a; 37 ll ans=10000090,rx=0,ry=0; 38 for(int i=t-1;i<=t+1;i++) 39 { 40 ll tmp=sabs(x+b/gong*i)+sabs(y-a/gong*i); 41 if(tmp<ans) ans=tmp,rx=sabs(x+b/gong*i),ry=sabs(y-a/gong*i); 42 } 43 if(!flag)printf("%lld %lld ",rx,ry); 44 else printf("%lld %lld ",ry,rx); 45 } 46 return 0; 47 }