poj 2412 The Balance 【exgcd】By cellur925

题目传送门

一遇到数学就卡住,我这是怎么肥4...(或许到图论会愉悦吧,逃)

 

Description

* 给出两种重量为的 AB 的砝码,给出一种使用最少的砝码的方
式,称出重量 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\n",rx,ry);
44         else printf("%lld %lld\n",ry,rx);
45     }
46     return 0;
47 }
View Code

 

posted @ 2018-09-28 18:03  cellur925&Chemist  阅读(147)  评论(0编辑  收藏  举报