[NOI2018]屠龙勇士
题面:Luogu
题解:
首先我们发现,每一次打longge龙的剑是可以算出来的,所以全部丢到\(multiset\)里就好了
于是我们要求解的就是
\[\begin{cases}
K_1x\equiv a_1~(~mod~p_1) \\
K_2x\equiv a_2~(~mod~p_2) \\
K_3x\equiv a_3~(~mod~p_3) \\
\dots
\end{cases}
\]
我们考虑如何求一个方程
\[K_1x\equiv a_1~(~mod~p_1) \\
K_1x+P_1y=a_1~(\because a_1|\gcd(K_1,p_1)) \\
let~K_1Sx+P_1Sy=gcd \\
x\equiv \frac{a_1}{\gcd(K_1,p_1)}Sx~(~mod~\frac{p_1}{\gcd(K_1,p_1)})
\]
其中\(Sx\)可以\(exgcd\)求出来
然后我们把这些方程转化成了标准形式,套\(excrt\)即可
但是这题细节贼多
首先,如果某个时候\(a_i>p_i\),那么可能我们虽然没把这条龙打到0以下,但血量的确满足方程要求
这时候我们发现数据范围保证如果有这种情况,必定有\(p_i=1\)
所以直接一路取\(max\)即可,也就是
\[ans=\max_{i=1\sim n}(\left \lceil \frac{a_{i}}{K_i} \right \rceil)
\]
其次,上面那个过程中,如果\(a_i\not|\gcd(K_i,p_i)\),就直接puts("-1")
即可
\(excrt\)合并时也是如此
最后,这题中间会爆\(long~long\),所以要上龟速乘法
如果最后答案小于\(mx\),则要补到满足条件的最小值,也就是\(ans+m\left \lceil \frac{mx-ans}{m} \right \rceil\)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T& x)
{
x = 0; char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 100005
#define ll long long
multiset<ll> s;
multiset<ll>::iterator it;
ll a[maxn], p[maxn], b[maxn];
ll x, y, Gcd;
ll exgcd(ll a, ll b, ll& x, ll& y)//求逆元,顺便返回gcd(a,b)
{
if (!b) { x = 1, y = 0; return a; }
ll tp = exgcd(b, a % b, y, x);
y -= a / b * x;
return tp;
}
inline ll qmul(ll a, ll b, ll p)
{
ll ans = 0;
for (; b; b >>= 1, a = (a + a) % p)
if (b & 1) ans = (ans + a) % p;
return ans;
}
int main()
{
ll T, n, m, mx, ans, tp, k;
read(T);
while (T--)
{
read(n), read(m); s.clear();
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(tp), s.insert(tp);
mx = ans = 0; m = 1;
for (int i = 1; i <= n; ++i)
{
it = s.upper_bound(a[i]);
if (it != s.begin()) --it;
k = *it;
s.erase(it); s.insert(b[i]);
mx = max(mx, 1ll * (a[i] - 1) / k + 1);
k %= p[i], a[i] %= p[i];
if (!k && a[i]) { puts("-1"); goto End; }
if (!k && !a[i]) continue;//这个方程没用,直接跳掉
Gcd = exgcd(k, p[i], x, y);//求出gcd(K_i,p_i)和一个特解
if (a[i] % Gcd) { puts("-1"); goto End; }
p[i] /= Gcd;
a[i] = qmul(a[i] / Gcd, (x % p[i] + p[i]) % p[i], p[i]);//转化方程
Gcd = exgcd(m, p[i], x, y);
if ((a[i] - ans) % Gcd) { puts("-1"); goto End; }
m = m / Gcd * p[i];
ans = (ans + qmul(qmul(m / p[i], ((a[i] - ans) % m + m) % m, m), (x % m + m) % m, m)) % m;//合并
}
printf("%lld\n", ans >= mx ? ans : ans + m * ((mx - ans - 1) / m + 1));
End:;
}
return 0;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.