[NOI2018]屠龙勇士
嘟嘟嘟
今天复习一下excrt,还算是没忘。
这道题,首先用set预处理一下,找到斩杀每条龙用哪把刀。
然后能列出方程\(ATK_i * x - p_i y = a_i\)。这显然是一个不定方程,用exgcd搞一下就行。然后我就想,怎么把所有解合并。假设一个特解是\(x'\),那么通解就是\(x = x' + k * \frac{p_i}{gcd(ATK_i, p_i)}\),就可以写成\(x \equiv x' (mod \ \frac{p_i}{(ATK_i, p_i)})\)。然后这一堆就可以用excrt搞了。
看数据范围,会发现有些坑点,就是存在\(a_i > p_i\)的情况。这会导致你把巨龙的血耗到大于0的情况,却刚好是\(p_i\)的倍数,这显然是杀不死龙的。但在excrt中这是一个合法解。
然而所有这些情况,都满足\(p_i = 1\),那么答案就是\(max_{i = 1} ^ {n} \lceil \frac{a_i}{ATK_i} \rceil\)。
最后因为不会用set,把s.upper_bound(a[i])写成了upper_bound(s.begin(), s.end(), a[i]),后面点全TLE了,而前面的点竟然还能A。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
#include<set>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m;
ll a[maxn], p[maxn], t[maxn], atk[maxn];
multiset<ll> s;
In void work0()
{
ll ans = 0;
for(int i = 1; i <= n; ++i) ans = max(ans, (a[i] + atk[i] - 1) / atk[i]);
write(ans), enter;
}
#define snew multiset<ll>::iterator
snew it;
In bool init()
{
for(int i = 1; i <= n; ++i)
{
it = s.begin();
if(*it > a[i]) atk[i] = *it, s.erase(it);
else
{
it = s.upper_bound(a[i]), --it;
atk[i] = *it, s.erase(it);
}
s.insert(t[i]);
}
for(int i = 1; i <= n; ++i) if(a[i] > p[i]) {work0(); return 1;}
return 0;
}
ll A[maxn], B[maxn];
In ll mul(ll a, ll b, ll mod)
{
ll d = (long double) a / mod * b + 1e-8;
ll ret = a * b - d * mod;
return ret < 0 ? ret + mod : ret;
}
In void exgcd(ll a, ll b, ll& x, ll& y, ll& d)
{
if(!b) d = a, x = 1, y = 0;
else exgcd(b, a % b, y, x, d), y -= a / b * x;
}
In bool solve()
{
for(int i = 1; i <= n; ++i)
{
ll x, y, d;
exgcd(atk[i], p[i], x, y, d);
if(a[i] % d) return 0;
ll tp = p[i] / d;
x = mul((x % tp + tp) % tp, a[i] / d, tp);
A[i] = x, B[i] = tp;
}
return 1;
}
In ll excrt()
{
ll ans = A[1], M = B[1];
for(int i = 1; i <= n; ++i)
{
ll x, y, d, c = ((A[i] - ans) % B[i] + B[i]) % B[i];
exgcd(M, B[i], x, y, d);
if(c % d) return -1;
ll tp = B[i] / d;
x = mul((x % tp + tp) % tp, c / d, tp);
ans += x * M, M *= tp, ans %= M;
}
return ans;
}
int main()
{
int T = read();
while(T--)
{
n = read(), m = read();
s.clear();
for(int i = 1; i <= n; ++i) a[i] = read();
for(int i = 1; i <= n; ++i) p[i] = read();
for(int i = 1; i <= n; ++i) t[i] = read();
for(int i = 1, x; i <= m; ++i) x = read(), s.insert(x);
if(init()) continue;
write(solve() ? excrt() : -1), enter;
}
return 0;
}