exgcd,crt,excrt_拓展欧几里得算法,中国剩余定理,拓展中国剩余定理

拓展欧几里得算法

877. 扩展欧几里得算法 - AcWing题库

模板

def exgcd(a,b):
    if b == 0:  return a, 1, 0
    d, x, y = exgcd(b, a%b)
    return d, y, x - a // b * y

def main():
    n = int(input())
    for i in range(n):
        a, b = map(int, input().split())
        d, x, y = exgcd(a,b)
        tx, ty = b // d, a // d
        k = ceil((1-x) / tx)
        x += k * tx
        y -= k * ty
        print(x,y)

P1082 [NOIP2012 提高组] 同余方程 

求最小正整数解,需要放缩x,x通解如下方定理2 ,由“输入数据保证一定有解”,得gcd(a,b)| 1,所以gcd(a,b) ==1,x通解为 x = x_{0}+tb,所以答案为 x_{0}\ mod \ b

878. 线性同余方程 - AcWing题库

标准的模板,对于方程右侧的bi,我们exgcd直接求出的x,y是对应于ax+by = gcd(a,b)的,所以要对求得的x,y进行放缩,数论是研究整数性质的,若b不为gcd(a,b)的倍数,即是无解情况,否则对x,y乘以系数 b/gcd(a,b),即为结果。

若要求得具有特殊性质的结果,例如正数解,负数解,最小整数解,看下个例题。

P5656 【模板】二元一次不定方程 (exgcd) 

对于题目中所谓的方程正负解,是指两个解都为正或负,若求得最小正x对应的y为负值,即为有整数解但没有正整数解

x有通解 x = x_{0}+t*\frac{b}{gcd(a,b)} ,记d = gcd(a,b),记kx = b/d

kx可求,放缩的倍数t1是未知数,对于最小正整数解,满足x >= 1,代入通解可求得放缩倍数t为 t_{1} = ceil((1-x_{0}) / kx),现通解方程中不含未知数,代入即可得到Xmin,或者可以代入原方程求解。

y放缩的倍数 t1 和x 是一样的,所以对y的特解操作也可以求得Xmin对应的Y,注意y的通解是减去,与x是相对的。最小正x对应最大正y, 所以求得了 Xmin 和 Ymax

同样思路求 Ymin,然后求Xmax

正整数解的个数求 最大的解Xmax或Ymax到最小的解之间包含几个kx或ky,然后+1即可

代码里可能变量名不太一样,注意一下(不想改了,,

def main():
    a, b, c = map(int, input().split())
    d, x, y = exgcd(a,b)
    if c % d != 0:
        print(-1)
        return
    # 放缩得 特解
    x, y = x * c // d, y * c // d 
    # 通解系数
    tx, ty = b // d, a // d
    # 放缩倍率
    k1 = ceil((1-x)/tx)
    # 求得最小x最大y
    xmin = x + tx * k1
    ymax = y - ty * k1
    # 求另一对
    k2 = ceil((1-y)/ty)
    ymin = y + ty * k2
    xmax = x - tx * k2
    # 最大y非正情况
    if ymax <= 0:
        print(xmin,ymin)
    else:        
        cnt = (ymax - ymin) // ty + 1
        print(cnt,xmin,ymin,xmax,ymax)

对二元一次不定方程的通解,有如图定理


中国剩余定理

P1495 【模板】中国剩余定理(CRT)

M = \prod_{1}^{n}m_{i} \qquad M_{i} = \frac{M}{m_{i}} \\ \\ans = \sum_{1}^{n} a_{i}*M_{i}*inv(M_{i},m_{i})(mod\ M)

逆元用exgcd求

def exgcd(a, b):
    if b == 0:
        return a, 1, 0
    d, x, y = exgcd(b, a % b)
    return d, y, x - a//b * y

def main():
    n = int(input())
    a, m = [0] * (n+2),[0] * (n+2)
    M = 1
    for i in range(n):
        m[i],a[i] = map(int,input().split())
        M *= m[i]
    ans = 0
    for i in range(n):
        mi = M // m[i]
        d,x,y = exgcd(mi,m[i])
        ans += a[i] * x * mi
    print(ans)

拓展中国剩余定理 

P4777 【模板】扩展中国剩余定理(EXCRT)

上个问题中的模数不再为两两互质的整数P4777 【模板】扩展中国剩余定理(EXCRT) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

def excrt():
    n = int(input())
    a,m = [0] * (n), [0] * (n)
    for i in range(n):
        m[i], a[i] = map(int,input().split())
    while len(m) > 1:
        m1,m2 = m.pop(),m.pop()
        a1,a2 = a.pop(),a.pop()
        d = gcd(m1,m2)
        lcm = (m1*m2) // d
        if (a2-a1) % d != 0:
            print(-1)
            return
        d,x,y = exgcd(m1//d,m2//d)
        k1 = ((a2-a1)//d * x) % lcm
        tmp = (a1 + k1 * m1) % lcm
        a.append(tmp)
        m.append(lcm)
    print(a[0])

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值