1.首先是gcd,最大公因子。求两个数的最大公因子有很多中方法,其实是殊途同归。我们就说一说最简单并且容易实现的欧几里得算法吧。
2.欧几里得算法:它是一个递归的算法,gcd(a,b)=gcd(b,a%b).证明也不难:口糊一下:假设k是a,b的最大公因子,那么k|a&&k|b。这是等式左边,至于右边,我们只需要证明k|a%b即可。我们把a%b写成:a-b*(a/b)那么显然,k是整除它的。所以等式成立。这个递归的出口就是当有一个数据是0,那么gcd就是另外一个非0的数据,因为gcd(a,0)=a.代码也是很简洁,复杂度是log级别甚至更低。
#define ll long long
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
3.exgcd:就是拓展欧几里得算法。它是用来解二元不定方程的。(当然,你说它可以求逆元我也不反对)。我们首先看一个这样的问题:ax+by=c.(没错,这是一条直线,但是我们现在不再解析几何里面讨论它)。这个方程一定有整数解吗?这似乎是一个棘手的问题。不过没关系,有个人告诉了我们这样的一个结论:ax+by=gcd(a,b),这个方程一定是有整数解的。这个人就是裴蜀。OK,知道了这个东西,我们对于ax+by=c这个方程就好办了,假设gcd(a,b)=d;我们对于等式两边同时除以d:(a/d)x+(b/d)x=(c/d)。显然,等式左边一定是一个整数,那么等式右边也要视一个整数,所以我们找到了这个等式存在整数接的必要条件:d|c。并且我们也可以证明这个条件是充分的。我们知道了这些,我们如何求得这个解呢?我们还是从ax+by=gcd(a,b)入手。
4.ax+by=gcd(a,b)的解法:解这个方程我们就需要用到了欧几里得算法了:首先我们知道:ax1+by1=gcd(a,b),又由欧几里得算法我们可以知道:gcd(a,b)=gcd(b,a%b),所以我们可以得出第二个方程:bx2+a%by2=gcd(b,a%b)=ax1+by1.这样x1就可以转移到x2一直到递归结束。那么递归结束是什么时候呢?我们知道:欧几里得算法递归的出口是有一个数据为0了。这里也是:如果b为0,得到的方程就是ax=a,x=1.那么我们可以得到一组解:x=1,y=0。这样就可以实现整个问题的求解。代码如下:
long long exgcd(long long a, long long b, long long &x, long long &y)
{
long long d, t;
if (b == 0) { x = 1; y = 0; return a; }
d = exgcd(b, a % b, x, y);
//这里就是我们能根据转移的式子退出来的结果,大家可以自己手推一下。
t = x - a / b * y;
x = y;
y = t;
return d;
}
当我们解决了ax+by=gcd(a,b)之后,解决ax+by=c就很简单了,让等式缩小d倍解完再扩大即可
5.说了这么多。看个问题吧。题目链接。中文题就不在多说了,我们直接考试分析:我们假设x=(A/B)%9973.令c=9973,我们把这个模意义下的式子展开:x+kc=A/B.继续整理:Bx+kBc=A.这是第一个式子,又因为n=A%c,我们继续展开:n+tc=A.联立着连个式子:Bx-n=(t-kB)c。令t-kB=y,整理:Bx-cy=n.--->(B/n)x-(c/n)y=1=gcd(B,c),所以这个式子一定有解。套个公式即可,但是这里显然是小题大做了,当我们知道Bx-n=(t-kB)c的时候,我们就可以写成:(Bx-n)%c=0.枚举x很快就可以得到答案。