天后我才改完D2T1, 是真的菜啊我
.
步入正题 这道题由于杀龙顺序是一定的 首先我们可以用一个
来维护每一条龙被攻击力为多少的剑所杀 处理出杀每条龙的剑之后 我们发现这就是很多个
这样的方程 我们可以通过
把它转换成
如果你还不会
可以看这篇博客
对了 对于这个题我们应该采用数据分治
我们的做法都是基于
的条件下
观察数据表可以发现 不满足
的点可以直接算
那么大力特判掉这种情况就可以过掉此题啦
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll a[maxn], p[maxn], K[maxn], M[maxn], X[maxn], B[maxn];
ll n, m, nowx, nowb = 1, minn;
multiset<ll>::iterator it;
multiset<ll> Tree;
ll mul(ll a, ll b, ll mod) {
ll res = 0, f = 1;
if(b < 0) b *= (f = -1);
while(b) {
if(b & 1)
(res += a) %= mod;
b >>= 1, (a <<= 1) %= mod;
}
return res * f;
}
ll ex_gcd(ll a, ll &x, ll b, ll &y) {
if(!b) {
x = 1, y = 0;
return a;
}
ll gcd = ex_gcd(b, x, a % b, y);
ll xx = y, yy = x - a / b * y;
x = xx, y = yy;
return gcd;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("4774.in", "r", stdin);
freopen("4774.out", "w", stdout);
#endif
ll T, x, y;
for(scanf("%lld", &T); T -- ; ) {
bool flag = 0, fuck = 0;
Tree.clear();
nowx = 0, nowb = 1, minn = 0;
scanf("%lld%lld", &n, &m);
For(i, 1, n) scanf("%lld", &a[i]);
For(i, 1, n) {
scanf("%lld", &p[i]);
if(p[i] != 1)
fuck = 1;
}
For(i, 1, n) scanf("%lld", &M[i]);
For(i, 1, m) {
scanf("%lld", &x);
Tree.insert(x);
}
For(i, 1, n) {
it = Tree.upper_bound(a[i]);
if(it != Tree.begin()) -- it;
K[i] = *it, Tree.erase(it);
ll gcd = ex_gcd(K[i], X[i], p[i], y);
if(a[i] % gcd != 0) {
flag = 1;
break;
}
minn = max(minn, ll(ceil(1.0 * a[i] / K[i])));
B[i] = p[i] / gcd;
X[i] = mul(X[i], a[i] / gcd, B[i]);
X[i] = (X[i] + B[i]) % B[i];
Tree.insert(M[i]);
}
if(!fuck) {
printf("%lld\n", minn);
continue;
}
if(flag) {
puts("-1");
continue;
}
For(i, 1, n) {
ll gcd = ex_gcd(nowb, x, B[i], y);
if((X[i] - nowx) % gcd != 0) {
flag = 1;
break;
}
x = mul(x, (X[i] - nowx) / gcd, B[i] / gcd);
x = (x + B[i] / gcd) % (B[i] / gcd);
nowx = nowb * x + nowx;
nowb = (nowb / gcd * B[i]);
nowx %= nowb;
}
if(flag) {
puts("-1");
continue;
}
printf("%lld\n", nowx);
}
return 0;
}