首先,我们可以用
multiset
m
u
l
t
i
s
e
t
求出杀死每一条龙所用的剑。设它的攻击力为
attacki
a
t
t
a
c
k
i
。然后,我们发现题目转化成了:求
的最小非负整数解。
我们将
attacki
a
t
t
a
c
k
i
移到等式右边,式子转化为
这就构成了 扩展中国剩余定理 扩 展 中 国 剩 余 定 理 的一般形式。直接求解即可。
此题的细节较多,请注意以下几点:
- 当 attacki a t t a c k i 和 pi p i 不互素的情况下无法快速求出 attack−1i a t t a c k i − 1 。这时,根据模运算的消去律,可以将 ai,pi,attacki a i , p i , a t t a c k i 同时除以 gcd(ai,pi,attacki) g c d ( a i , p i , a t t a c k i ) 。此时若 attacki a t t a c k i 和 pi p i 仍不互素,则一定无解。
- 在求解答案时可能需要对两个 1012 10 12 级别的数进行乘法取模运算,此时需要用到 “快速乘”(倍增乘法)。
- 最后算出来的答案不一定能使得所有龙的体力值降到非正值,所以要将答案不停的加上 lcmni=1pi l c m i = 1 n p i 直到合法。
#include <cstdio>
#include <set>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 100005;
int T, n, m;
ll a[maxn], p[maxn], atk[maxn], sword[maxn];
void upd(ll &x, ll y, ll mod) {
if ((x += y) >= mod) {
x -= mod;
}
}
ll mult(ll a, ll b, ll mod) {
a = (a % mod + mod) % mod;
b = (b % mod + mod) % mod;
ll res = 0;
for (; b; b >>= 1, upd(a, a, mod)) {
if (b & 1) {
upd(res, a, mod);
}
}
return res;
}
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
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 inverse(ll a, ll mod) {
ll x, y;
exgcd(a, mod, x, y);
return (x % mod + mod) % mod;
}
ll excrt(ll *A, ll *B, ll *M, ll &res) {
res = 0;
ll lcm = 1;
for (int i = 1; i <= n; i++) {
ll a = mult(A[i], lcm, M[i]);
ll b = B[i] - mult(A[i], res, M[i]);
ll d = gcd(a, M[i]);
if (b % d != 0) {
res = -1;
return 0;
}
ll x = mult(b / d, inverse(a / d, M[i] / d), M[i] / d);
res += lcm * x, lcm *= M[i] / d;
}
res = (res % lcm + lcm) % lcm;
return lcm;
}
int main() {
for (scanf("%d", &T); T--; ) {
multiset<ll> S;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", a + i);
}
for (int i = 1; i <= n; i++) {
scanf("%lld", p + i);
}
for (int i = 1; i <= n; i++) {
scanf("%lld", atk + i);
}
for (int i = 1; i <= m; i++) {
ll x;
scanf("%lld", &x);
S.insert(x);
}
ll mx = 0;
for (int i = 1; i <= n; i++) {
multiset<ll>::iterator it = S.upper_bound(a[i]);
if (it != S.begin()) {
it--;
}
sword[i] = (*it), S.erase(it), S.insert(atk[i]);
mx = max(mx, (a[i] + sword[i] - 1) / sword[i]);
}
ll x, lcm = excrt(sword, a, p, x);
if (x != -1 && x < mx) {
x += lcm * ((mx - x + lcm - 1) / lcm);
}
printf("%lld\n", x);
}
return 0;
}