[NOI2018] 屠龙勇士

题意

求解下列同余方程组,

{b1xa1(modm1)b2xa2(modm2)bnxan(modmn)

其中,n105,mi108,lcm(mi)1012,ai1012,bi106

Solution

不难发现,此方程组和exCRT模板有异曲同工之妙,尝试用相同的办法进行化简

考虑到exCRT的解产生的同余方程不带有前缀系数,考虑如下同余方程组,

{xa1(modm1)bxa2(modm2)

展开得,

k1×bm1k2×m2=a1ba2

该式子左侧类似裴蜀定理, 则存在 λ1,λ2 满足 λ1×bm1+λ2×m2=gcd(bm1,m2)

gcd(bm1,m2)a1ba2 时, 方程组无解.

gcd(bm1,m2)a1ba2 时, 存在 k1,k2 满足 k1×bm1k2×m2=a1ba2.

则特解 x=a1ba2gcd(bm1,m2)×λ1×m1, 根据CRT的相关内容,得到通解

x=a1ba2gcd(bm1,m2) λ1 m1+k1lcm(m1,m2)

考虑由多个同余方程组成的方程组,上面通解可表达成

xa1ba2gcd(bm1,m2) λ1 m1(modlcm(m1,m2))

由此,从原方程组中依次选出一个同余方程进行合并,显然不失一般性。

考虑第一组方程如何求解,显然存在 x0(mod1) ,可用于求解第一个同余方程。

Code

点击查看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;

const int N = 1e5 + 50;
typedef long long lld;

inline lld read() {
	register lld w = 0, f = 1;
	register char c = getchar();
	while (c > '9' || c < '0') {
		if (c == '-')  f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		w = w * 10 + c - '0';
		c = getchar();
	}
	return w * f;
}

multiset <lld> S;

int n, M;
lld m[N], a[N], b[N], atk[N];

inline lld gcd(lld a, lld b) {
	return !b ? a : gcd(b, a % b);
}

inline lld exgcd(register lld a, register lld b, lld &x, lld &y) {
	if (!b) {
		x = 1;
		y = 0;
		return a;
	}
	register lld d = exgcd(b, a % b, x, y);
	register lld tmp = x;
	x = y;
	y = tmp - a / b * y;
	return d;
}

inline lld mul(register lld a, register lld b, register lld p) {
	lld ans = 0;
	while (b) {
		if (b & 1)  ans = (ans + a) % p;
		a = (a + a) % p;
		b >>= 1;
	}
	return ans;
}

lld a1, m1;

int main() {
	int T = read();
	while (T--) {
		bool allone = 1;
		n = read(), M = read();
		S.clear();
		for (register int i = 1; i <= n; ++i)  a[i] = read();
		for (register int i = 1; i <= n; ++i) {
			m[i] = read();
			if (m[i] != 1)  allone = 0;
		}
		for (register int i = 1; i <= n; ++i)  atk[i] = read();
		for (register int i = 1; i <= M; ++i) {
			register lld x = read();
			S.insert(x);
		}

		for(int i = 1; i <= n; ++i) {
			auto u = S.upper_bound(a[i]);
			if(u != S.begin()) u--;
			b[i] = *u;
			S.erase(u);
			S.insert(atk[i]);
		}

		if (allone) {
			register lld maxa = 0;
			for (register int i = 1; i <= n; ++i)  maxa = max(maxa, (lld)ceil(1.0 * a[i] / b[i]));
			printf("%lld\n", maxa);
			continue;
		}

		a1 = 0;
		m1 = 1;
		for (register int i = 1; i <= n; ++i) {
			lld x, y;
			lld g = exgcd(mul(b[i], m1, m[i]), m[i], x, y);
			x = (x % m[i] + m[i]) % m[i];
			lld C = (a[i] - mul(b[i], a1, m[i]) + m[i]) % m[i];
			if (C % g != 0) {
				printf("-1\n");
				goto ed;
			}
			lld tmp = m[i] / g * m1;
			a1 = (a1 + mul(mul(C / g, x, m[i] / g), m1, tmp)) % tmp;
			m1 = tmp;
		}
		
		printf("%lld\n", a1);
		ed:;
	}
	return 0;
}

后记

最近写数学题全是bug🤮🤮🤮

希望过几天手能够更稳一点吧

posted @   A_Big_Jiong  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示