您的位置:首页 > 其它

数论基础知识小结

2016-11-01 10:06 183 查看
窝来大致说一下数论的一些东西:

1.欧几里得相关的两个定理:

欧几里得原理:(a,b)=(b,a mod b)

证明:

设r=a mod b,then a=kb+r

设c为a,b的任意公因数

则:c|a;c|b;c|(a−kb) <=> c|r

所以c也是b,r的因数

同理,我们设d为b,r的任意因数,则可知d也是a,b的公因数。

设A={d|a and d|b},B={d|r and d|b}, thenA=B

所以我们可以知道(a,b)=(b,r)

证明完毕!

代码如下:

int gcd(int x,int y){return y ? (y,x % y) : x;}


扩展欧几里得算法:

贝祖等式x,y∈Z,则ax+by=(a,b)有解。

证明:

我们可以直接用扩展欧几里得算法步骤来证明:

根据(a,b)=(b,a mod b)

则设:

ax1+by1=(a,b)

bx2+(a mod b)y2=(b,a mod b)

所以:ax1+by1=bx2+(a mod b)y2

根据取模的定义,我们知道a mod b=a−⌊ab⌋⋅b

那么可以把等式右边替换:

ax1+by1=bx2+(a−⌊ab⌋⋅b)y2

我们知道,如果这样一直递归下去,那么肯定会使得y的系数为0。

这样子就能证明有解了。

那么怎么计算出方程的值呢?

我们根据递归出口:

when b==0,then x=1,y=0

理由如下:

ax+by=(a,b)=a,则x=1,y=0必然是一组解。

回到刚刚得问题上:

ax1+by1=bx2+(a−⌊ab⌋⋅b)y2

我们现在已经知道了右边等式的系数都是多少,现在怎么知道x1和y1的值呢?

移项:

a(x1−y2)+b(y1−x2+⌊ab⌋⋅y2)=0

那么显然有:

x1=y2;y1=x2−⌊ab⌋⋅y2

那么我们可以得出算法代码:

void exgcd(int a,int b,int &x,int &y){b ? (exgcd(b,a % b,y,x),y -= a / b * x): (x = 1,y = 0);}


中场休息时间QAQ

中国剩余定理:

内容如下:

假如有n个同余方程:

x≡ai(mod mi),且mi两两互素。

设M=∏mi

求其在模M意义下的解。

我们假设Mi=M/mi

再设ti为Mi在模mi下的逆元,即tiMi=1(mod mi)

那么我们就可以方程的解:

x=∑aitiMi

证明:

先证明x合法。

即证明∀i∈[1,n],x≡ai(mod mi)。

x=∑j≠iajtjMj+aitiMi

则在mod mi的意义下:

x=∑0+ai=ai(mod mi)

这样x是合法的。

实际上,我们可以肯定x是小于M的。

因为如果x=∑aitimi>M合法,那么显然可以把M减去对吧。

我们这样就得到模M意义下的一个解了.

但是……

注意一下实际上我们是用CRT去求解同余方程组的。

所以我们应该没有必要那么麻烦。

我们考虑把同余方程合并:

对于x≡r1modm1

x≡r2modm2

那么我们想把它合成为1个方程。

k1m1+r1=k2m2+r2

k1m1−k2m2=r2−r1

可以扩欧来求,对吧。

当d=gcd(m1,m2)/|(r2−r1)时,无解。

我们想让这个k1尽量小,并且是正整数。

那么显然的恒等式是:

k1m1+k2m2+lcm(k1,k2)−lcm(k1,k2)=r2−r1

k1(m1%k2d)+k2(m2+p)=r2−r1

这个p显然是补足m1少了的那部分的,具体值懒得算了。

所以我们可以注意到,这个m1显然可以在模意义下去搞。

这样我们就求出了一个x,注意到,x+lcm(m1,m2)显然是通解,那么实际上我们的方程就变成了:

x=r2−r1(mod lcm(m1,m2))

这样一个一个合并就好了。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define Rep(i,n) for(int i = 1;i <= n;++ i)
using namespace std;
typedef long long LL;
LL m[1002],r[1002];
int n;
LL gcd(LL a,LL b){return b ? gcd(b,a % b) : a;}
void exgcd(LL a,LL b,LL &x,LL &y){b ? (exgcd(b,a % b,y,x),y -= a / b * x) : (x = 1,y = 0);}
LL crt()
{
LL R,M,k1,k2;
R = r[1],M = m[1];
for(int i = 2;i <= n;++ i)
{
LL dt = r[i] - R,d = gcd(m[i],M);
if(dt % d)return -1;
exgcd(M / d,m[i] / d,k1,k2);
k1 = (k1 * dt / d) % (m[i] / d);
R = R + k1 * M;
M = M / d * m[i];
R %= M;
}
return R < 0 ? R + M : R;
}
int main()
{
while(~scanf("%d",&n))
{
Rep(i,n)scanf("%lld%lld",&m[i],&r[i]);
printf("%lld\n",crt());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: