【数学 扩展中国剩余定理】luogu_4777 扩展中国剩余定理 POJ_2891 Strange Way to Express Integers

题意

给定 a , b a,b a,b
{ x ≡ b 1 ( m o d   a 1 ) x ≡ b 2 ( m o d   a 2 ) x ≡ b 3 ( m o d   a 3 ) . . . x ≡ b n ( m o d   a n ) \left\{\begin{matrix}x\equiv b_1(mod\ a_1) \\ x\equiv b_2(mod\ a_2) \\ x\equiv b_3(mod\ a_3) \\... \\ x\equiv b_n(mod\ a_n) \end{matrix}\right. xb1(mod a1)xb2(mod a2)xb3(mod a3)...xbn(mod an)
x x x的最小非负整数解。

思路

假设已经求出了前 k − 1 k-1 k1个方程构成的方程组的一个解 x x x。记 m m m为前面所有 a i a_i ai的乘积(代码中 m m m为前面所有 a i a_i ai l c m lcm lcm,不影响后面的结论),则 x + i ∗ m ( i ∈ Z ) x+i*m(i \in\mathbb{Z}) x+im(iZ)是前 k − 1 k-1 k1个方程的通解。

考虑第 k k k个方程,求出一个整数 t t t使得 x + t ∗ m ≡ b k ( m o d   a k ) x+t*m\equiv b_k(mod\ a_k) x+tmbk(mod ak)。该方程等价于 m ∗ t ≡ b k − x ( m o d   a k ) m*t\equiv b_k-x(mod\ a_k) mtbkx(mod ak),其中 t t t是未知量。这就是一个线性同余方程,可以用扩展欧几里得算法判断是否有解,并求出它的解。若有解,则 x ′ = x + t ∗ m x'=x+t*m x=x+tm就是前 k k k个方程构成的方程组的一个解。

故做 n n n e x g c d exgcd exgcd可得出答案。

代码

#include<cstdio>
#include<algorithm>

int n;
long long x, y;
long long a[100001], b[100001];

long long exgcd(long long a, long long b, long long &x, long long &y) {
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	long long d = exgcd(b, a % b, x, y);
	long long z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}

long long mul(long long a, long long b, long long p) {
	long long ans = 0;
	for (; b; b >>= 1) {
		if (b & 1) ans = (ans + a) % p;
		a = a * 2 % p;
	}
	return ans;
}

long long excrt() {
	long long m = a[1], ans = b[1];
	for (int i = 2; i <= n; i++) {
		long long c = ((b[i] - ans) % a[i] + a[i]) % a[i], d = exgcd(m, a[i], x, y);//求解方程mt+ya[k]=(m,a[k])
		if (c % d) return -1;//有解当且仅当(m,a[k])|b[k]-x
		long long k = a[i] / d;
		x = mul(x, c / d, k);//求解方程mt+ya[k]=b[k]-x
		ans = ans + x * m;
		m *= a[i] / d;
	}
	return (ans % m + m) % m;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%lld %lld", &a[i], &b[i]);
	printf("%lld", excrt());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值