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

题意

给定a,ba,ba,b
{x≡b1(mod a1)x≡b2(mod a2)x≡b3(mod a3)...x≡bn(mod an)\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)
xxx的最小非负整数解。

思路

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

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

故做nnnexgcdexgcdexgcd可得出答案。

代码

#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());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值