题意理解错了。。。

一把剑打一条龙,打了$x$次后如果龙不死,你就Game Over了。

显然,面对每条龙使用的剑是固定的,如果所有龙中有一条没打死你就挂了。

可以知道,可行的答案集合就是所有龙的可行集合的交集。

考虑当前面对第$i$条龙,若要打死它,$x$满足条件:$a_{i} - x * v_{i} + y * p_{i} = 0$,其中$a$是血量,$v$是攻击力,$p$是恢复力,$y$是某非负整数。

可以把它转化为同余式:$a_{i} \equiv x * v_{i} (mod \; p_{i})$。我们要找出满足该条件的$x$的最小正整数值。

通常情况下,只要先算$v_{i}$在$(mod \; p_{i})$意义下的逆元即可,但此时两者不互质,不一定存在逆元,根据数论某定理:$ a * c \equiv b * c (mod \; m) \Rightarrow a \equiv b (mod \; m / ( c , m ) $,我们先除去三者的$gcd$,再求逆元就可以了,如果此时仍然没有逆元,则无解。(这里有一个要注意的事情,当$p_{i}=1$的时候会出点问题,特判就可以了)

可以发现,$x$可以的取值是一个等差数列,我们需要把$n$个等差数列合并起来,取它们的交集。

假设我们即将合并的两个等差数列为$(a_{s}, d_{s}),(a_{i},d_{i})$,其中$a$为首项,$d$为公差。

合并后的公差比较好算:$lcm(d_{s},d_{i})$。主要考虑如何求第一个数同时出现在两个等差数列中了。

可以列出以下等式:$a_{s} + x * d_{s} = a_{i} + y * d_{i}$,其中$x, y$都是某个非负整数。

移项转化为同余式:$x * d_{s} \equiv a_{i} - a_{s} (mod \; d_{i})$,和刚刚的套路一样就可以解出$x$的值啦。

最后显然$a_{s}$就是我们想要的答案。(提示:由于中间答案过大,使用中精度存储,也可以用快速乘)

Update :

求同余式$x * a \equiv b (mod \; p)$的另一种思路,设$d = gcd(a, p)$,那有解当且仅当$d | b$。具体证明就是扩展欧几里得相关。

那该同余方程等价于$x * \frac{a}{d} \equiv \frac{b}{d} (mod \; \frac{p}{d})$。此时由于$\frac{b}{d}$一定与$\frac{p}{d}$互质,通过求逆元直接解出$x$即可。

$\bigodot$技巧&套路:

  • 基础数论,同余式$x * a \equiv b (mod \; p)$求解的技巧。
#include <cstdio>
#include <set> typedef long long LL;
const int N = ; int tc, n, m;
LL ai[N], di[N], a[N], p[N], b[N], v[N];
std::multiset<LL> S; inline LL Mul(LL a, LL b, LL p) {
a %= p; b %= p;
LL a0 = a & , a1 = a >> ;
return (((a1 * b % p) << ) + a0 * b) % p;
}
LL Ex_gcd(LL a, LL b, LL &x, LL &y) {
if (b == ) return x = , y = , a;
LL g = Ex_gcd(b, a % b, y, x);
y -= a / b * x;
return g;
} inline LL Get(LL x, LL re = ) {
auto it = S.upper_bound(x);
if (it != S.begin()) --it;
re = *it; S.erase(it);
return re;
} int main() {
scanf("%d", &tc);
for (; tc; --tc) {
S.clear();
scanf("%d%d", &n, &m);
for (int i = ; i <= n; ++i) scanf("%lld", &a[i]);
for (int i = ; i <= n; ++i) scanf("%lld", &p[i]);
for (int i = ; i <= n; ++i) scanf("%lld", &b[i]);
for (int i = ; i <= m; ++i) scanf("%lld", &v[i]), S.insert(v[i]); LL as = , ps = ;
for (int i = ; i <= n; ++i) {
LL vi = Get(a[i]), x, y, ai, pi;
LL d = Ex_gcd(vi, p[i], x, y);
if (a[i] % d != ) {
as = -; break;
}
x = (x % (p[i] / d) + p[i] / d) % (p[i] / d);
ai = Mul(a[i] / d, x, p[i] / d);
pi = p[i] / d;
if (p[i] == ) ai = a[i] / vi + (bool)(a[i] % vi);
S.insert(b[i]);
if (pi == ) {
if (as < ai) {
LL bl = (ai - as) / ps + (bool)((ai - as) % ps);
as = as + bl * ps;
}
continue;
}
LL dir = ((ai - as) % pi + pi) % pi;
d = Ex_gcd(ps, pi, x, y);
if (dir % d != ) {
as = -; break;
}
x = (x % (pi / d) + pi / d) % (pi / d);
LL nx = Mul(dir / d, x, pi / d);
as = as + nx * ps;
ps = ps / d * pi;
} printf("%lld\n", as);
} return ;
}

【NOI 2018】屠龙勇士(扩欧)的更多相关文章

  1. [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士

    [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士 题意 题面好啰嗦啊直接粘LOJ题面好了 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照 ...

  2. 洛谷P4774 [NOI2018]屠龙勇士 [扩欧,中国剩余定理]

    传送门 思路 首先可以发现打每条龙的攻击值显然是可以提前算出来的,拿multiset模拟一下即可. 一般情况 可以搞出这么一些式子: \[ atk_i\times x=a_i(\text{mod}\ ...

  3. NOI 2018 屠龙勇士 (拓展中国剩余定理excrt+拓展欧几里得exgcd)

    题目大意:略 真是一波三折的一道国赛题,先学了中国剩余定理,勉强看懂了模板然后写的这道题 把取出的宝剑攻击力设为T,可得Ti*x=ai(mod pi),这显然是ax=c(mod b)的形式 这部分用e ...

  4. NOI 2018网络同步赛(游记?)

    刚中考完那段时间比较无聊,报名了一个同步赛,报完名才发现成绩单是要挂到网上的,而且因为报的早给了一个很靠前的考号...那布星啊,赶紧学点东西,于是在一周内学了网络流,Treap以及一些数论. Day1 ...

  5. 洛谷 P4774 [NOI2018] 屠龙勇士

    链接:P4774 前言: 交了18遍最后发现是多组数据没清空/ll 题意: 其实就是个扩中. 分析过程: 首先发现根据题目描述的选择剑的方式,每条龙对应的剑都是固定的,有查询前驱,后继(在该数不存在前 ...

  6. NOI2018屠龙勇士(扩展CRT + splay(multiset))

    QWQ 一到假期就颓废 哎 今年新鲜出炉的NOI题,QwQ同步赛的时候写的,后来交了一发洛谷,竟然过了 首先 根据题目,我们很容易得到,假设对应每一条龙的剑的攻击力是\(atk\)的话 \[a_i-x ...

  7. 【POJ】2115 C Looooops(扩欧)

    Description A Compiler Mystery: We are given a C-language style for loop of type for (variable = A; ...

  8. BZOJ5418[Noi2018]屠龙勇士——exgcd+扩展CRT+set

    题目链接: [Noi2018]屠龙勇士 题目大意:有$n$条龙和初始$m$个武器,每个武器有一个攻击力$t_{i}$,每条龙有一个初始血量$a_{i}$和一个回复值$p_{i}$(即只要血量为负数就一 ...

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

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

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

    题意 LOJ #2721. 「NOI2018」屠龙勇士 题解 首先假设每条龙都可以打死,每次拿到的剑攻击力为 \(ATK\) . 这个需要支持每次插入一个数,查找比一个 \(\le\) 数最大的数(或 ...

随机推荐

  1. Unity Shader 学习之旅之SurfaceShader

    Unity Shader 学习之旅之SurfaceShader unity shader 图形图像  如果大地的每个角落都充满了光明 谁还需要星星,谁还会 在夜里凝望 寻找遥远的安慰——江河 官方文档 ...

  2. 使用CNN做数字识别和人脸识别

    上次写的一层神经网络也都贴这里了. 我有点困,我先睡觉,完了我再修改 这个代码写法不太符合工业代码的规范,仅仅是用来学习的的.还望各位见谅 import sys,ossys.path.append(o ...

  3. Netty源码分析第4章(pipeline)---->第5节: 传播outbound事件

    Netty源码分析第五章: pipeline 第五节: 传播outBound事件 了解了inbound事件的传播过程, 对于学习outbound事件传输的流程, 也不会太困难 在我们业务代码中, 有可 ...

  4. IDEA配置maven中央库

    分两步: STEP :配置maven: STEP :配置IDEA.区分默认配置和项目级配置. STEP 1:maven中央库配置 国内常用的maven库主要是阿里云maven库.华为云maven. 其 ...

  5. ats 分层缓存

    了解缓存层次结构 缓存层次结构由彼此通信的缓存级别组成.ats支持多种类型的缓存层次结构. 所有缓存层次结构都识别父和子的概念. 父缓存是层次结构中较高的缓存, ats可以 将请求转发到该缓存.子缓存 ...

  6. Python3入门机器学习 - k近邻算法

    邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代 ...

  7. Python更新库

    查看系统里过期的python库,可以用pip命令 [root@vnode33 sim-enb-sgi]# pip list #列出所有安装的库 Package Version ------------ ...

  8. Ipython使用

    目录 Ipython说明 Ipython使用 安装使用 TAB键自动补全 内省(?命令) 执行系统命令(!) 与操作系统交互 %run命令执行文件代码 %paste %cpaste命令执行剪贴板代码 ...

  9. a标签的href为空的问题

    在表格里写一个a标签链接刷新表格的时候,没注意,把a标签的href设置为""空字符串,导致每次刷新表格之后会再刷新一次整体页面,找了很久都没发现问题出在哪里,最后无意之间,鼠标在一 ...

  10. 2018-2019-20172329 《Java软件结构与数据结构》第七周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 <Java软件结构与数据结构>第十一章-二叉查找树 一.概述 1.什么是二 ...