数论基础知识小结

窝来大致说一下数论的一些东西:
1.欧几里得相关的两个定理:
欧几里得原理: (a,b)=(b,a mod b)
证明:

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

ca,b

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

cb,r

db,rda,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,yZ,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=aabb

那么可以把等式右边替换:
ax1+by1=bx2+(aabb)y2

我们知道,如果这样一直递归下去,那么肯定会使得y的系数为0。
这样子就能证明有解了。
那么怎么计算出方程的值呢?
我们根据递归出口:
when b==0,then x=1,y=0

理由如下:
ax+by=(a,b)=ax=1,y=0

回到刚刚得问题上:
ax1+by1=bx2+(aabb)y2

我们现在已经知道了右边等式的系数都是多少,现在怎么知道 x1y1?
移项:
a(x1y2)+b(y1x2+aby2)=0

那么显然有:
x1=y2;y1=x2aby2

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

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个同余方程:

xai(mod mi)mi

M=mi
求其在模 M 意义下的解。
我们假设
Mi=M/mi

再设 tiMimi ,即 tiMi=1(mod mi)
那么我们就可以方程的解:
x=aitiMi

证明:
先证明x合法。
i[1,n],xai(mod mi)

x=jiajtjMj+aitiMi

则在 mod mi
x=0+ai=ai(mod mi)

这样x是合法的。
实际上,我们可以肯定x是小于M的。
因为如果 x=aitimi>MM
我们这样就得到 M 意义下的一个解了.
但是……
注意一下实际上我们是用CRT去求解同余方程组的。
所以我们应该没有必要那么麻烦。
我们考虑把同余方程合并:
对于
xr1modm1

xr2modm2

那么我们想把它合成为1个方程。
k1m1+r1=k2m2+r2

k1m1k2m2=r2r1

可以扩欧来求,对吧。
d=gcd(m1,m2)/|(r2r1) 时,无解。
我们想让这个 k1 尽量小,并且是正整数。
那么显然的恒等式是:
k1m1+k2m2+lcm(k1,k2)lcm(k1,k2)=r2r1

k1(m1%k2d)+k2(m2+p)=r2r1

这个 p 显然是补足m1少了的那部分的,具体值懒得算了。
所以我们可以注意到,这个 m1 显然可以在模意义下去搞。
这样我们就求出了一个 x ,注意到,x+lcm(m1,m2)显然是通解,那么实际上我们的方程就变成了:
x=r2r1(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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值