同余方程

线性(一次)同余方程

axc(modb) --> axc=by(yZ) -> axby=c,求x的最小非负整数解。

扩展欧几里得算法

Bezout定理a,bZ,x,yZ, 满足ax+by=gcd(a,b)

推导证明:
exgcd递归到边界时,b=0,显然有a1+00=gcd(a,0)->令x=1,y=0.
考虑递归返回过程,gcd(a,b)=gcd(b,a%b).假设存在x,y满足bx+(a%b)y=gcd(b,a%b),因为a%b=aba/b,所以有ay+b(xa/by=gcd(a,b)),那么新的一组解为X=y,Y=xa/by

对于更一般的情况,ax+by=c,当且仅当gcd(a,b)|c,方程有整数解。这时,只需给x,y乘上c/gcd即可。
更进一步,方程的通解表示为

x=cgcdx0+kbgcdy=cgcdy0kagcd(kZ)

证明:

 x1=cgcdx0,y1=cgcdy0 ax+by=ax1+by1=ca(xx1)=b(y1y)agcd(xx1)=bgcd(y1y)gcd(agcd,bgcd)=1xx1=kbgcd,y1y=kagcdx=x1+kbgcd,y=y1kagcd

inline int exgcd(int a, int b, int& x, int& y)//a*x + b*y = 1;
{
    if (b == 0) { x = 1, y = 0; return a; }
    int gcd = exgcd(b, a % b, x, y);
    int z = x;
    x = y, y = z - a / b * y;
    return gcd;
}
inline int exgcd(int a, int b, int& x, int& y)//a*x + b*y = 1;
{
    if (b == 0) { x = 1, y = 0; return a; }
    int gcd = exgcd(b, a % b, y, x);//直接交换传参
    y -= a / b * x;
    return gcd;
}
inline int solve(int a, int b, int c)//a*x + b*y = c;
{
    int x, y, g = exgcd(a, b, x, y);
    if (c % g) return -1;//无解
    a /= g, b /= g, c /= g;
    //只要求x为最小非负整数解,而y可以为负数
    x = (x * c % b + b) % b;
    return x;
    //x和y都要求为非负整数解
    while (x > 0 || y < 0) x -= b, y += a;
    x = -x, y = y;
}

高次同余方程

axb(modp)(a,p)互质,求解x的最小非负整数解。

BSGS(Baby Step, Giant Step)算法

x=itj,其中t=pj[0,t1],则方程变为aitjb(modp),进一步有(at)ibaj(modp)

对于所有的j,把baj(modp)全部插入hash表,枚举i,计算出(at)i,在hash表中查找,如果有,更新答案。最优时间复杂度为t=p,为O(p)。

int BSGS(int a, int b, int p)//a^x≡b (mod p)
{
    map <int, int> hash; hash.clear();//多次调用时,把map定义放在外面
    b %= p;
    int t = sqrt(p) + 1;
    for (int j = 0; j < t; ++j) hash[b * qpow(a, j, p) % p] = j;
    a = qpow(a, t, p);
    if (a == 0) return b == 0 ? 1 : -1;
    for (int i = 0; i <= t; ++i)
    {
        int val = qpow(a, i, p);
        int j = hash.find(val) == hash.end() ? -1 : hash[val];
        if (j >= 0 && i * t - j >= 0) return i * t - j;
    }
    return -1;//无解
}

一元线性同余方程组

{xa1(modm1)xa2(modm2)xan(modmn)

中国剩余定理(物不知数)

m1,m2,,mn两两互质时,设M=i=1nmi,ci=Mmi,ti是线性同余方程citi1(modmi)的一个解,也就是ci(modmi)意义下的逆元。那么x在模M有唯一解x=i=1naiciti(modM),有通解x=kM+i=1naiciti(kZ)

证明

对于所有ji,因为cj=Mmj,所以因数中包含mi,所以cj0(modmi),也即ajcjtj0(modmi)。因为citi1(modmi),所以aicitiai(modmi),那么i=1naicitiai(modmi)。同理可知x满足所有n个方程,解成立。

int CRT(int n, int a[], int m[])//中国剩余定理
{
    int M = 1, ans = 0;
    for (int i = 1; i <= n; ++i) M *= m[i];
    for (int i = 1; i <= n; ++i)
    {
        int c = M / m[i], t, y;//除m[i]以外所有模数的倍数
        exgcd(c, m[i], t, y);//c*t≡1(mod m[i])
        ans += a[i] * c * t % M;//∑ a[i]*c[i]*t[i]
        ans = (ans % M + M) % M;
    }
    return ans;
}

扩展中国剩余定理(模数不互质)

先来考虑只有两个方程的情况。设方程分别是xa1(modm1)xa2(modm2),则得到不定方程x=m1p+a1=m2q+a2
移项得m1pm2q=a2a1,首先当gcd(m1,m2)(a2a1),方程无解;否则,可以得到一组可行解pq。令a=m1p+a1M=lcm(m1,m2),合并得到同余方程xa(modM),多个方程的话两两合并即可。

int calc(int a, int b, int c)//ax+by=c
{
    int x, y, d = exgcd(a, b, x, y);
    if (c % d) return -1;
    a /= d, b /= d, c /= d;
    return (x * c % b + b) % b;
}
int EXCRT(int n, int a[], int m[])//扩展中国剩余定理
{
    int M = 1, ans = 0;
    for (int i = 1; i <= n; ++i)
    {
        int x = calc(M, m[i], a[i] - ans);//M*x≡a[i]-ans(mod m[i])
        if (x == -1) return -1;//判断无解
        ans += x * M;//∑ ans+x[i]*M
        M = lcm(M, m[i]);//更新前i个数的lcm
        ans = (ans % M + M) % M;
    }
    return ans;
}
posted @   sandom  阅读(181)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示