题意

LOJ #2721. 「NOI2018」屠龙勇士

题解

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

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

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

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

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

\[\begin{cases}
x \times ATK_1 \equiv a_1 \pmod {p_1} \\
~~~~~~~~~~~~~~~~~~~~~ \vdots \\
x \times ATK_n \equiv a_n \pmod {p_n} \\
\end{cases}
\]

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

如果把 \(ATK_i\) 除到右边去,也就是

\[x \equiv \frac{a_i}{ATK_i} \pmod {p_i}
\]

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

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

但是这个有点特殊情况,也就是 \(\gcd(ATK_i, a_i, p_i) > 1\) 的时候,需要约去 \(gcd\) 。

比如 \(2x \equiv 8 \pmod {36}\) 的时候,显然 \(x = 4\) 是其中的一个解,但 \(2\) 对于 \(36\) 没有逆元。

但将方程转化后 \(x \equiv 4 \pmod {18}\) 就是等价于原来方程的另一个可行方程。

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

还有一个地方对于 \(p_i = 1\) 的情况,解出来是 \(x \equiv 0 \pmod {1}\) 。这个需要给答案有一个下界 \(a_i\) ,最后要一直加上 \(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;
}

LOJ #2721. 「NOI2018」屠龙勇士(set + exgcd)的更多相关文章

  1. loj#2721. 「NOI2018」屠龙勇士

    题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...

  2. LOJ 2721 「NOI2018」屠龙勇士——扩展中国剩余定理

    题目:https://loj.ac/problem/2721 1.注意别一输入 p[ i ] 就 a[ i ] %= p[ i ] ,因为在 multiset 里找的时候还需要真实值. 2.注意用 m ...

  3. 「NOI2018」屠龙勇士

    「NOI2018」屠龙勇士 题目描述 小\(D\)最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照编号\(1-n\)顺序杀掉\(n\) 条巨龙,每条巨龙拥有一个初始的生命 值ai .同时 ...

  4. 「NOI2018」屠龙勇士(EXCRT)

    「NOI2018」屠龙勇士(EXCRT) 终于把传说中 \(NOI2018D2\) 的签到题写掉了... 开始我还没读懂题目...而且这题细节巨麻烦...(可能对我而言) 首先我们要转换一下,每次的 ...

  5. POJ1061 青蛙的约会 和 LOJ2721 「NOI2018」屠龙勇士

    青蛙的约会 Language:Default 青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 133470 Accep ...

  6. 「NOI2018」屠龙勇士 解题报告

    「NOI2018」屠龙勇士 首先对于每个龙用哪个剑砍,我们可以用set随便模拟一下得到. 然后求出拿这个剑砍这条龙的答案 \[ atk_ix-p_iy=a_i \] 其中\(atk_i\)是砍第\(i ...

  7. 「NOI2018」屠龙勇士(CRT)

    /* 首先杀每条龙用到的刀是能够确定的, 然后我们便得到了许多形如 ai - x * atki | pi的方程 而且限制了x的最小值 那么exgcd解出来就好了 之后就是扩展crt合并了 因为全T调了 ...

  8. loj#2718. 「NOI2018」归程

    题目链接 loj#2718. 「NOI2018」归程 题解 按照高度做克鲁斯卡尔重构树 那么对于询问倍增找到当前点能到达的高度最小可行点,该点的子树就是能到达的联通快,维护子树中到1节点的最短距离 s ...

  9. Loj #2719. 「NOI2018」冒泡排序

    Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...

随机推荐

  1. Redis对象占用内存分析

    当你往Redis中插入了一系统对象,如何分析这些对象的占用情况? 1.我们可以在Redis的控制台使用info命令来查看各项指标,其中有一项是Memory,可以通过存储前后的used_memory差异 ...

  2. SJP's Blog

    This is SJP's blog. Here is a mirror web of his blog.

  3. [JSOI2016]无界单词[动态规划、kmp]

    题意 题目链接 分析 对于第一问,枚举最终串最小的相同前后缀来统计答案. 由于最小的相同前后缀也是无界单词,所以可以考虑先求解子问题. 定义状态 \(f(i)\) 表示长度为 \(i\) 的串中有多少 ...

  4. C# 根据部分属性来判断俩个对象是否相同

    根据部分属性来判断俩个对象是否相同 代码是第一版本 可能不牢固 有问题请反馈一下 3QU 效果图: public static class CustomExpand { public static b ...

  5. SpringBoot日记——分布式篇

    思考:什么是分布式?什么是微服务? 一些概念:RPC-远程过程调用,某台机器想要调用另一台机器所需要的一种服务,及分布式的服务框架,比如dubbo或者SpringCloud. 铺天盖地的分布式互联网系 ...

  6. Supervisor (进程管理利器) 使用说明 - 运维笔记

    一.Supervisor简单介绍supervisor是一个 Client/Server模式的系统,允许用户在类unix操作系统上监视和控制多个进程,或者可以说是多个程序.supervisor与laun ...

  7. Centos7.5部署MySQL5.7基于GTID主从复制+并行复制+半同步复制+读写分离(ProxySQL) 环境- 运维笔记 (完整版)

    之前已经详细介绍了Mysql基于GTID主从复制的概念,原理和配置,下面整体记录下MySQL5.7基于GTID主从复制+并行复制+增强半同步复制+读写分离环境的实现过程,以便加深对mysql新特性GT ...

  8. 《linux内核设计与实现》第五章

    第五章 系统调用 一.与内核通信 系统调用在用户空间进程和硬件设备之间添加了一个中间层.作用: 为用户空间提供了一种硬件的抽象接口. 系统调用保证了系统的稳定和安全. 每个进程都运行在虚拟系统中,而在 ...

  9. linux及安全第六周总结

    进程控制块pcb——task_struct 操作系统三大功能: 进程管理(核心) 内存管理 文件系统 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息: 进程状态 ...

  10. 如何实现基于ssh框架的投票系统的的质量属性

    如何实现基于ssh框架的投票系统的的质量属性: 项目 :网上考试系统 我做的是网上考试系统,因为标准化的考试越来越重要,而通过计算机进行标准化判卷,系统会自动判卷出成绩,组织考试的人不用组织人员打印试 ...