「NOI2018」屠龙勇士 link
思路:
把取出的宝剑攻击力设为T,可得 Ti*x=ai(mod pi),
这显然是ax=c(mod b)的形式,
这部分用exgcd求解x的最小正整数解先把a,b,c除以gcd(a,b),
如果c不能整 除gcd(a,b)那么无解。
此时a,b互质,用 exgcd求得a的逆元,
逆元乘回来gcd(a,b)就是x的最小正整数解,
注意可能爆long long要用龟速乘那么此时
求得x是仅仅对于这一个方程的,
我们要把它带到excrt的板子中求得x关于所有方程
都成立的最小正整数解即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
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;
}