传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1356
由题意,就是要解一个不定方程ax+by=d,要求(abs(x)+abs(y))最小。
一.exgcd
先从exgcd说起。由裴蜀定理可知,ax+by=gcd(a,b)必定存在整数解(x,y)。那么有:
ax+by=gcd(a,b)=gcd(b,a%b)=bx'+(a%b)y' (1.1)
其中等号1,3用到了裴蜀定理,等号2用到了gcd的性质。
由a%b=a-a/b(本文中所有的除法都是整数除法)那么我们把等式最右边变形,可以得到:
ax+by=bx'+ay'-(a/b)y'=ay'+b(x'-(a/b)*y') (1.2)
于是得到一组解:
x=y' (1.3)
y=x'-(a/b)*y' (1.4)
所以可以用递归的方式求解。
最后考虑一下边界条件,当b==0时,从线性同余方程的角度看x=1,y=0显然是一组可行解。
1 | int exgcd(int a,int b,int &x,int &y){ |
二.求通解
再考虑这道题,等号右边并不是gcd,而是一个d,因为题目告诉你一定有解,所以gcd一定是d的因子,我们把x和y都乘上一个rate=(d/gcd(a,b)),得到一组初始的
x0=x*rate (2.1)
y0=y*rate (2.2)
接下来就要去找对x0和y0加加减减,来求这个MIN(abs(x0+dx)+abs(y0-dy))。
我们先考虑
再考虑dx和dy的关系:
a*x0+b*y0=d (2.3)
对方程变形得到:
a*(x0+dx)+b*(y0-dy)=d (2.4)
把里面的式子提出来得到:
a*dx-b*dy=0 (2.5)
那么就是:
dx/dy=b/a (2.6)
考虑gcd(a,b),可以得到:
dx/dy=(b/gcd)/(a/gcd) (2.7)
此时(b/gcd)与(a/gcd)是互质的所以可以取到的最小的dx和dy就是:
dx=(b/gcd) (2.8)
dy=(a/gcd) (2.9)
那么方程的通解一定满足如下条件:
ansx=x0+k*dx (2.10)
ansy=y0-k*dy (2.11)
三.问题转化
知道了通解,那么哪一组解才是最优的呢?
因为dx!=dy,不妨设dx>dy,我们假设此时x满足
|x|>>|dx|(>>表示远大于)
那么我们让
x+=t*dx (3.1)
y-=t*dy (3.2)
在x和y均不变号的情况下,答案会变小t*(dx-dy),是一组更优的解。所以最优解一定满足:
|x|<|dx| (3.3)
那么问题就可以转化为变成了求方程关于x的最小正整数解。
但是问题在于,根据式(3.3),去掉绝对值后,x可能是负的。但是问题在于,我们要求的方程
a*x+b*y=d (3.4)
可以变形为
y=(d-a*x)/b (3.5)
我们上面已经证明,通过上述方程构造出来的x,上面方程中的y一定是有解的,那么对于一个确定的x,我们总希望y最小,因为dx>dy,那么如果x取到负数,那么一定会大大增加y的值,所以很有可能会更糟。所以我们只要考虑x取最小正整数的情况就可以了。(我直言了,我不会证明,但是我的直觉告诉我这样做很对,oj也告诉我这样做很对)。
反之,如果dy>dx,那么考虑y的最小正整数解即可。
四.求最小正整数解
那这就非常容易了(说白了就是取模):
ansx=(ansx%dx+dx)%dx
然后用式(3.5):
ansy=(d-a*ansx)/b
就完事了。
五.贴代码
看清题意,多写两个if就完事了
1 |
|