屠龙勇士题解(系数不为一的同余方程组解法)

1.前言

还是对扩展中国剩余定理不熟,稍微变了一下就蒙了……

2.题解

首先用各种方法找到每条龙对应的剑。

根据题意,可以列出一下方程

\[atk_ix \equiv a_i \pmod {p_i} \]

发现我们平时的扩展中国剩余定理有一个美妙的要求 \(atk_i = 1\),所以我们要拼尽全力去满足这个要求。


我们先不考虑必须把龙的生命值打成非正数这个条件。

我们要表达原方程中 \(x\) 的取值,\(x\) 可取的条件是 \(\exists y \in Z, 满足 atk_ix + p_i y = a_i\),则我们用扩展欧几里得解出 \(x\) 的一组特解\((x')\)后,可得 \(x \in \{x''\mid x'' = x' + k \frac{p_i}{gcd (p_i, atk_i)},k \in Z \}\),所以 \(x \equiv x' \pmod {\frac{p_i}{gcd (p_i, atk_i)}}\),现在,他不就是一个系数为一的同余方程了吗?

然后,我们记用扩展中国剩余定理合并后的同余方程组变为了 \(x \equiv b \pmod {m}\),则 \(x \in \{x' \mid x' = b + km, k \in Z \}\),则我们只需要在这个解集中找到一个满足要求(将所有龙的生命值打成非整数)的数,即在解集中找到最小的大于等于\(\max {\lceil \frac{a_i}{atk_i} \rceil}\)的数即可。

#include <set>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define PLL pair <LL, LL>
#define MP(x,y) make_pair (x, y)

template <typename T> void read (T &x) { x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return; }
template <typename T> void write (T x) { if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0'); }
template <typename T> void print (T x, char ch) { write (x); putchar (ch); }
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }

const int Maxe = 1e5;
int Num_E;
struct Equation {
	LL Mod, b;
}Eq[Maxe + 5];
LL md (LL x, LL MO) {
	return (x % MO + MO) % MO;
}
LL gcd (LL x, LL y) {
	if (y == 0) return x;
	else return gcd (y, x % y);
}
LL lcm (LL x, LL y) {
	return x / gcd (x, y) * y;
}
LL mul (LL x, LL y, LL Mod) {
	LL res = 0;
	while (y) {
		if (y & 1) res = (res + x) % Mod;
		x = (x + x) % Mod; y >>= 1;
	}
	return res;
}
void exgcd (LL a, LL b, LL &x, LL &y) {
	if (b == 0) {
		x = 1; y = 0;
		return ;
	}
	exgcd (b, a % b, y, x);
	y -= (a / b) * x; 
}
LL solve (LL a, LL b, LL c) {
	LL _gcd = gcd (a, b);
	c = (c % b + b) % b;
	if (c % _gcd != 0) return -1;
	
	LL x, y;
	exgcd (a, b, x, y);
	LL p = b / _gcd;
	x = (x % p + p) % p;
	x = mul (x, (c / _gcd), p);
	return x;
}
LL quick_pow (LL x, LL y, LL Mod) {
	LL res = 1;
	while (y) {
		if (y & 1) res = mul (res, x, Mod);
		x = mul (x, x, Mod); y >>= 1;
	}
	return res;
}
PLL Excrt () {//求同余方程组的模板
	LL Mod = 1, b = 0;
	for (int i = 1; i <= Num_E; i++) {
		LL res = solve (Mod, Eq[i].Mod, Eq[i].b - b);
		if (res == -1) {
			return MP (-1, -1);
		}
		LL M = lcm (Mod, Eq[i].Mod);
		b = (b + res * Mod % M) % M;
		Mod = M; 
	}
	return MP (b, Mod);
}

const int Maxn = 1e5;

int t, n, m;
LL a[Maxn + 5], p[Maxn + 5], sword[Maxn + 5];

multiset <LL> atk;

int main () {
//	freopen ("dragon.in", "r", stdin);
//	freopen ("dragon.out", "w", stdout);
	
	read (t);
	while (t--) {
		atk.clear ();
		
		read (n); read (m);
		for (int i = 1; i <= n; i++) read (a[i]);
		for (int i = 1; i <= n; i++) read (p[i]);
		for (int i = 1; i <= n; i++) read (sword[i]);
		for (int i = 1; i <= m; i++) {
			int x; read (x);
			atk.insert (x);
		}
		
		Num_E = n; 
		bool flag = 0; LL _max = 0;
		for (int i = 1; i <= n; i++) {
			//这里我用的是 multiset 找到对应的剑
			auto it = atk.upper_bound (a[i]);
			if (it != atk.begin ()) it--;
			_max = Max (_max, (LL)ceil (a[i] * 1.0 / *it));
			//找到至少要攻击多少次
			LL x, y;
			LL _gcd = gcd (p[i], *it);
			if (a[i] % _gcd != 0) {
				//裴蜀定理,没有满足要求的解
				flag = 1;
				break;
			}
			exgcd (*it, p[i], x, y);
			LL Mod = p[i] / _gcd;
			x = md (x, p[i]);
			//x : 求出一个特解
			//Mod : 求出周期
			Eq[i].b = mul (x, a[i] / _gcd, p[i]);
			Eq[i].Mod = Mod;
			atk.erase (it);
			atk.insert (sword[i]);
		}
		if (flag == 1) {
			print (-1, '\n');
			continue;
		}
		PLL res = Excrt ();
		//res = (特解,模数的 lcm (周期))
		if (res.first == -1) {
			print (-1, '\n');
			continue;
		}
		res.first += ceil ((_max - res.first) * 1.0 / res.second) * res.second;
		//修正答案
		print (res.first, '\n');
	}
	return 0;
}
posted @ 2021-08-25 09:58  C2022lihan  阅读(207)  评论(0编辑  收藏  举报