NOI2018 屠龍勇士
阿新 • • 發佈:2021-07-18
\(\text{Analysis}\)
這題怎麼做非常明顯
依照關卡迴圈,然後利用資料結構維護當天用的劍(如權值線段樹或平衡樹,建議 \(set\))
通過一元同餘方程解出當前關卡的答案(沒有或有無數個,用通解表示)
把每個關卡答案的通解聯立起來,就有了一堆同餘方程組
擴充套件中國剩餘定理求解即可
注意無解情況的判斷(即解方程時)
\(\text{Code}\)
#include<cstdio> #include<iostream> #define LL long long using namespace std; const int N = 1e5 + 5, Len = 1e6; int n, m; LL a[N], p[N], atk[N], tk[N]; inline void read(LL &x) { x = 0; LL f = 1; char ch = getchar(); while (ch < '0' || ch > '9') f = (ch == '-' ? -1 : f), ch = getchar(); while (ch >= '0' && ch <= '9') x = (x<<3)+(x<<1) + ch - '0', ch = getchar(); x *= f; } int seg[N << 5], ls[N << 5], rs[N << 5], size, rt; void update(int &p, int l, int r, int x, int v) { if (!p) p = ++size, ls[p] = rs[p] = seg[p] = 0; seg[p] += v; if (l == r) return; int mid = (l + r) >> 1; if (x <= mid) update(ls[p], l, mid, x, v); else update(rs[p], mid + 1, r, x, v); } int query_mi(int p, int l, int r, int x) { if (!seg[p]) return 0; if (l == r) return l; int mid = (l + r) >> 1, res = 0; res = query_mi(ls[p], l, mid, x); if (res) return res; if (x > mid) return query_mi(rs[p], mid + 1, r, x); } int query_mx(int p, int l, int r, int x) { if (!seg[p]) return 0; if (l == r) return l; int mid = (l + r) >> 1, res = 0; if (x > mid) res = query_mx(rs[p], mid + 1, r, x); if (res) return res; return query_mx(ls[p], l, mid, x); } LL exgcd(LL a, LL b, LL &x, LL &y) { if (!b){x = 1, y = 0; return a;} LL d = exgcd(b, a % b, x, y); LL tmp = x; x = y, y = tmp - (a / b) * y; return d; } LL fmul(LL x, LL y, LL P) { LL ret = 0; x %= P, y %= P; if (y < 0) y = (y + P) % P; for(; y; y >>= 1) { if (y & 1) ret = (ret + x) % P; x = x * 2 % P; } return ret; } LL exCRT(LL down) { LL A = a[1], P = p[1], M, x, y, d, c; for(int i = 2; i <= n; i++) { d = exgcd(P, p[i], x, y); if ((a[i] - A) % d) return -1LL; c = p[i] / d, x = (fmul(x, (a[i] - A) / d, c) + c) % c; M = P / d * p[i], A = (fmul(x, P, M) + A) % M, P = M; } if (A < down) A += ((down - x - 1) / M + 1) * M; return A; } inline LL solve() { rt = size = 0; for(register int i = 1; i <= m; i++) update(rt, 1, Len, atk[i], 1); LL A, c, x, y, d, knf = -1; for(register int i = 1; i <= n; i++) { A = query_mx(rt, 1, Len, min(a[i], (LL)Len)); if (!A) A = query_mi(rt, 1, Len, Len); if (p[i] == 1) { knf = max((a[i] - 1) / A + 1, knf), a[i] = 0, p[i] = 1; update(rt, 1, Len, A, -1), update(rt, 1, Len, tk[i], 1); continue; } if (a[i] && A % p[i] == 0) return -1LL; d = exgcd(A, p[i], x, y); if (a[i] % d) return -1LL; c = p[i] / d; a[i] = x = (fmul(x, a[i] / d, c) + c) % c, p[i] /= d; update(rt, 1, Len, A, -1), update(rt, 1, Len, tk[i], 1); } return exCRT(knf); } int main() { int T; scanf("%d", &T); for(; T; --T) { scanf("%d%d", &n, &m); for(register int i = 1; i <= n; i++) read(a[i]); for(register int i = 1; i <= n; i++) read(p[i]); for(register int i = 1; i <= n; i++) read(tk[i]); for(register int i = 1; i <= m; i++) read(atk[i]); printf("%lld\n", solve()); } }