LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)

题意

LOJ #2721. 「NOI2018」屠龙勇士

题解

首先假设每条龙都可以打死,每次拿到的剑攻击力为 ATK

这个需要支持每次插入一个数,查找比一个 数最大的数(或者找到 > 一个数的最小数),删除一个数。

这个东西显然是可以用 std :: multiset<long long> 来处理的(手写权值线段树或者平衡树也行)。

对于每一条龙我们只能刚好一次秒杀,并且要恰好算血量最后为 0(一波带走)。

然后就转化成求很多个方程:

{x×ATK1a1(modp1)                     x×ATKnan(modpn)

求最小正整数解 x 满足这些所有方程。

如果把 ATKi 除到右边去,也就是

xaiATKi(modpi)

就转化成求模线性方程组的最小整数解了,可以参考 我的数论总结 ,但是那个板子有个地方需要 慢速乘

这个需要用 exgcd 计算逆元,如果没有逆元那么对于这个方程是无解的。

但是这个有点特殊情况,也就是 gcd(ATKi,ai,pi)>1 的时候,需要约去 gcd

比如 2x8(mod36) 的时候,显然 x=4 是其中的一个解,但 2 对于 36 没有逆元。

但将方程转化后 x4(mod18) 就是等价于原来方程的另一个可行方程。

然后如果这个方程仍然没有逆元的话就是真的无解了。如果合并方程组中无解那也是无解。

还有一个地方对于 pi=1 的情况,解出来是 x0(mod1) 。这个需要给答案有一个下界 ai ,最后要一直加上 lcm 使得它不小于这个下界。

然后各种地方注意会爆 long long ,慢速乘就好了。(挂了 15pts 。。)

代码

#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << x << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; typedef long long ll; inline ll read() { ll x = 0, fh = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1; for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48); return x * fh; } void File() { #ifdef zjp_shadow freopen ("2721.in", "r", stdin); freopen ("2721.out", "w", stdout); #endif } void Exgcd(ll a, ll b, ll &x, ll &y) { if (!b) x = 1, y = 0; else Exgcd(b, a % b, y, x), y -= a / b * x; } inline ll Mult(ll x, ll y, ll Mod) { ll res = 0; y = (y % Mod + Mod) % Mod; for (; y; y >>= 1, (x += x) %= Mod) if (y & 1) (res += x) %= Mod; return res; } const int N = 1e5 + 1e3; namespace Equations { int n; ll mod[N], rest[N]; ll Solve() { For (i, 1, n - 1) { ll a = mod[i], b = mod[i + 1], c = rest[i + 1] - rest[i], gcd = __gcd(a, b), k1, k2; if (c % gcd) return - 1; a /= gcd; b /= gcd; c /= gcd; Exgcd(a, b, k1, k2); k1 = Mult(k1, c, b); mod[i + 1] = mod[i] / __gcd(mod[i], mod[i + 1]) * mod[i + 1] ; rest[i + 1] = (mod[i] * k1 % mod[i + 1] + rest[i] % mod[i + 1] + mod[i + 1]) % mod[i + 1]; } return rest[n]; } void Out() { For (i, 1, n) printf ("%lld %lld\n", mod[i], rest[i]); } }; multiset<ll> S; inline ll Find(ll x) { multiset<ll> :: iterator it = S.upper_bound(x); if (it != S.begin()) -- it; ll res = *it; S.erase(it); return res; } int n, m; ll a[N], p[N], atk[N], award[N]; inline ll Get_Inv(ll bas, ll Mod) { if (__gcd(bas, Mod) != 1) return -1; static ll x, y; Exgcd (bas, Mod, x, y); return (x % Mod + Mod) % Mod; } int main () { File(); int cases = read(); while (cases --) { n = read(); m = read(); For (i, 1, n) a[i] = read(); For (i, 1, n) p[i] = read(); For (i, 1, n) award[i] = read(); For (i, 1, m) { ll x = read(); S.insert(x); } For (i, 1, n) atk[i] = Find(a[i]), S.insert(award[i]); S.clear(); Equations :: n = n; bool flag = true; ll ans = 0, lcm = 1; For (i, 1, n) { ll gcd = __gcd(__gcd(atk[i], p[i]), a[i]); a[i] /= gcd; atk[i] /= gcd; p[i] /= gcd; if (p[i] == 1) { ans = max(ans, a[i] / atk[i] + (a[i] % atk[i] ? 1 : 0)); } ll tmp = Get_Inv(atk[i], p[i]); if (tmp == -1) { flag = false; break; } Equations :: mod[i] = p[i]; Equations :: rest[i] = Mult(a[i] % p[i], tmp % p[i], p[i]); lcm = lcm / __gcd(lcm, p[i]) * p[i]; } if (!flag) { puts("-1"); continue ; } ll tmp = Equations :: Solve(); if (tmp == -1) { puts("-1"); continue ; } if (tmp < ans) { ll gap = (ans - tmp) / lcm; tmp += gap * lcm; while (tmp < ans) tmp += lcm; while (tmp - lcm > ans) tmp -= lcm; } printf ("%lld\n", tmp); } #ifdef zjp_shadow cerr << (double) clock() / CLOCKS_PER_SEC << endl; #endif return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/9345637.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(253)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示