Solution
首先使用可支持 插入 / 删除 / 查找前驱及最小值 的数据结构,求出攻击第
i
i
条龙的攻击力 。
易得,能杀死第
i
i
条龙的条件是:
x×atki≡ai(modpi)
x
×
a
t
k
i
≡
a
i
(
mod
p
i
)
将第一个式子进行变形:
x≥⌈aiatki⌉
x
≥
⌈
a
i
a
t
k
i
⌉
如果存在一个 i i 使第二个式子(同余方程)无解,那么原问题无解。
否则解同余方程,得到解,形如:
把 n n 个方程放在一起,得到同余方程组。
这便是经典的扩展中国剩余定理(EXCRT)。
具体地,如果解出前 个方程的解 x≡R(modQ) x ≡ R ( mod Q ) ,
那么设前 i i 个方程的解为 。
那么有:
R+kQ≡ri(modqi)
R
+
k
Q
≡
r
i
(
mod
q
i
)
同样是一个线性同余方程。
最后可以得到无解,或者方程的通解:
x=kLCM(q1,q2,...,qn)+R
x
=
k
LCM
(
q
1
,
q
2
,
.
.
.
,
q
n
)
+
R
选取最小的大于等于 max⌈aatk⌉ max ⌈ a a t k ⌉ 的解。
Code
注意相乘时可能爆 long long ,要用快速乘。
作为一介场外选手,考场上没用 multiset 丢了 10 分 QwQ
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
typedef long long ll;
typedef multiset<ll>::iterator cyx;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
inline ll readll() {
ll res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5;
int n, m;
ll a[N], p[N], ba[N], at[N], atk[N], sol[N], atle, LCM;
multiset<ll> pyz;
void exgcd(ll a, ll b, ll &x, ll &y) {
if (!b) return (void) (x = 1, y = 0);
exgcd(b, a % b, y, x); y -= a / b * x;
}
ll qprod(ll a, ll b, ll MX) {
ll res = 0;
while (b) {
if (b & 1) res = (res + a) % MX;
a = a * 2 % MX;
b >>= 1;
}
return res;
}
ll solveth(ll atk, ll a, ll p, ll &w) {
ll g = __gcd(atk, p);
if (a % g) return -1;
atk /= g; a /= g; p /= g;
w = p; ll x, y;
exgcd(atk, p, x, y);
x = (x % p + p) % p;
return qprod(a, x, p);
}
void work() {
int i;
n = read(); m = read();
For (i, 1, n) a[i] = readll();
For (i, 1, n) p[i] = readll();
For (i, 1, n) ba[i] = readll();
For (i, 1, m) at[i] = readll();
pyz.clear();
For (i, 1, m) pyz.insert(at[i]);
For (i, 1, n) {
cyx it; ll tmp;
cyx xi = pyz.begin();
if ((tmp = (*xi)) > a[i])
pyz.erase(xi), atk[i] = tmp;
else it = pyz.upper_bound(a[i]),
atk[i] = (*--it), pyz.erase(it);
pyz.insert(ba[i]);
}
atle = 0;
For (i, 1, n) {
sol[i] = solveth(atk[i], a[i], p[i], p[i]);
if (sol[i] == -1) return (void) (puts("-1"));
atle = max(atle,
a[i] % atk[i] ? a[i] / atk[i] + 1 : a[i] / atk[i]);
}
LCM = p[1]; ll ans = sol[1];
For (i, 2, n) {
ll mov = ((sol[i] - ans) % p[i] + p[i]) % p[i];
ll g = __gcd(LCM, p[i]), x, y;
if (mov % g) return (void) (puts("-1"));
ll tm = LCM / g, Mod = p[i] / g; mov /= g;
exgcd(tm, Mod, x, y);
x = (x % Mod + Mod) % Mod;
ll k = qprod(mov, x, Mod), pl = LCM;
LCM = LCM / __gcd(LCM, p[i]) * p[i];
(ans += qprod(k, pl, LCM)) %= LCM;
}
ll spa = max(0ll, atle - ans);
ll k = spa % LCM ? spa / LCM + 1 : spa / LCM;
cout << ans + k * LCM << endl;
}
int main() {
int T = read(); while (T--) work();
return 0;
}