拓展欧几里得算法
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 ,由“输入数据保证一定有解”,得,所以
,x通解为
,所以答案为
878. 线性同余方程 - AcWing题库
标准的模板,对于方程右侧的bi,我们exgcd直接求出的x,y是对应于的,所以要对求得的x,y进行放缩,数论是研究整数性质的,若b不为gcd(a,b)的倍数,即是无解情况,否则对x,y乘以系数 b/gcd(a,b),即为结果。
若要求得具有特殊性质的结果,例如正数解,负数解,最小整数解,看下个例题。
P5656 【模板】二元一次不定方程 (exgcd)
对于题目中所谓的方程正负解,是指两个解都为正或负,若求得最小正x对应的y为负值,即为有整数解但没有正整数解
x有通解 ,记
,记
kx可求,放缩的倍数t1是未知数,对于最小正整数解,满足x >= 1,代入通解可求得放缩倍数t为 ,现通解方程中不含未知数,代入即可得到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)
逆元用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])