【题目链接】
【前置技能】
- 数据结构(线段树,平衡树,set,map等)
- 扩展中国剩余定理
【题解】
- 首先发现,用一个支持单点插入,询问lower_bound的数据结构维护一下,那么每条龙用哪一把剑其实是确定的。
- 那么问题其实就是求若干个形如 A T K i ∗ x ≡ a i ( m o d p i ) ATK_i*x \equiv a_i(mod~p_i) ATKi∗x≡ai(mod pi)的同余方程组的解。模数不一定互质,用扩展中国剩余定理合并,最后输出第一个大于等于答案下界的解。注意其中部分运算可能会爆longlong,需要使用快速乘。
- 时间复杂度 O ( Q N l o g N ) O(QNlogN) O(QNlogN)
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 100010
#define IT multiset <LL> :: iterator
using namespace std;
int Q, n, m;
LL a[MAXN], p[MAXN], b[MAXN], t[MAXN], x, y, C[MAXN], M[MAXN], lim;
multiset <LL> s;
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
void exgcd(LL a, LL b, LL &x, LL &y){
if (b == 0) {x = 1, y = 0; return;}
LL q = a / b, r = a % b;
exgcd(b, r, y, x);
y -= q * x;
}
LL gcd(LL a, LL b){
if (a == 0 || b == 0) return a + b;
else return gcd(b, a % b);
}
LL inv(LL a, LL b){
exgcd(a, b, x, y);
x = x % b;
if (x < 0) x += b;
return x;
}
LL mul(LL a, LL b, LL mod){
a %= mod, b %= mod;
if (a < 0) a += mod;
if (b < 0) b += mod;
LL ret = 0;
while (b){
if (b & 1) ret = (ret + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
if (ret < 0) ret += mod;
return ret;
}
LL excrt(int n){
int fla = 1;
for (int i = 2; i <= n; ++i){
LL m1 = M[i - 1], m2 = M[i], c1 = C[i - 1], c2 = C[i], tmp = gcd(m1, m2);
if ((c2 - c1) % tmp) {fla = 0; break;}
M[i] = m1 / tmp* m2;
LL tnp = inv(m1 / tmp, m2 / tmp), tp = ((c2 - c1) / tmp);
tnp = mul(tnp, tp, (m2 / tmp));
C[i] = mul(tnp, m1, M[i]);
C[i] = (C[i] + c1) % M[i];
if (C[i] < 0) C[i] = C[i] + M[i];
}
if (fla) {
if (C[n] >= lim) return C[n];
else {
LL ret = C[n];
ret = ret + ((lim - ret) / M[n]) * M[n];
while (ret < lim) ret += M[n];
while (ret - M[n] >= lim) ret -= M[n];
return ret;
}
} else return -1;
}
int main(){
read(Q);
while (Q--){
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(b[i]);
for (int i = 1; i <= m; ++i)
read(t[i]);
s.clear();
for (int i = 1; i <= m; ++i)
s.insert(t[i]);
int fla = 1;
lim = 1;
int cnt = 0;
for (int i = 1; i <= n; ++i){
++cnt;
IT tmp = s.begin();
if ((*tmp) < a[i]) {
tmp = s.end(); tmp--;
if ((*tmp) > a[i]){
tmp = s.upper_bound(a[i]);
tmp--;
}
}
LL cur = *tmp;
s.erase(tmp);
s.insert(b[i]);
if (p[i] == 1){
LL tmp = a[i] / cur;
if (a[i] % cur) ++tmp;
chkmax(lim, tmp);
--cnt;
} else {
LL tmp = a[i] / cur;
if (a[i] % cur) ++tmp;
chkmax(lim, tmp);
LL d = gcd(cur, p[i]);
if (a[i] % d) {printf("-1\n"); fla = 0; break;}
LL tt = cur / d, aa = a[i] / d, pp = p[i] / d;
C[cnt] = mul(aa, inv(tt, pp), pp), M[cnt] = pp;
}
}
if (fla) {
if (cnt == 0) printf("%lld\n", lim);
else printf("%lld\n", excrt(cnt));
}
}
return 0;
}