Solution
首先使用可支持 插入 / 删除 / 查找前驱及最小值 的数据结构,求出攻击第
条龙的攻击力
。
易得,能杀死第
条龙的条件是:
将第一个式子进行变形:
如果存在一个 使第二个式子(同余方程)无解,那么原问题无解。
否则解同余方程,得到解,形如:
把 个方程放在一起,得到 同余方程组。
这便是经典的 扩展中国剩余定理(EXCRT)。
具体地,如果解出前 个方程的解 ,
那么设前 个方程的解为 。
那么有:
同样是一个线性同余方程。
最后可以得到无解,或者方程的通解:
选取最小的大于等于 的解。
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() {
//freopen("dragon.in", "r", stdin);
//freopen("dragon.out", "w", stdout);
int T = read(); while (T--) work();
return 0;
}