写题解当作复习笔记
(这样就可以少写一篇博客了 Yeah)
# 题面
> Link LOJ 2721
# exCRT
「问题」
求解线性同余方程组
$$ \begin{cases} x\equiv a_1\pmod{m_1}\\ x\equiv a_2\pmod{m_2}\\ \cdots\\ x\equiv a_n\pmod{m_n} \end{cases} $$
$m$ 可以不互质。
考虑等价地合并两个同余方程:
可以把同余方程写为不定方程的形式,于是得到参数的一些关系:
由于 $m_1,m_2$ 不一定互质,所以关于 $k_1,k_2$ 的不定方程不一定有解。具体地说,设 $(m_1,m_2)=g$,则
等式左侧 $g\mid k_1m_1-k_2m_2$,则右侧也必须满足 $g\mid a_2-a_1$,否则无解。
若满足上述条件,则等式两边同时除以 $g$ 仍然等价,即
此时 $(m_1’,m_2’)=1$,可以直接用 exGCD 解决上述问题,得到 $k_1$ 的一个特解为 $k_0$。由
可以知道 $k_1$ 的通解为 $k_1=k_0+nm_2’(n\in\mathbb{Z})$。
将 $k_1$ 代回 $x$ 的表达式,则有
于是就得到了两个式子合并后的等价的式子。这样不断合并就可以得到最终 $x$ 的通解。
# 解析
一开始可以根据输入求出「用哪一把剑攻击第 $i$ 条龙」,记为 $w_i$。具体可以用 multiset 实现。
点击展开/折叠multiset使用技巧
multiset 内部每个位置储存了一个元素(并不是把相同的元素合到同一个位置并且记录次数),因此用迭代器 iterator 访问其中的某个位置,访问到的是单个元素。如果按迭代器顺序访问 multiset,就相当于把插入的所有元素排了个序。
multiset 内置有 lower_bound 和 upper_bound 函数,前者返回第一个大于等于给定值的元素的迭代器,后者返回第一个严格大于给定值的元素的迭代器。
multiset 的 delete 函数有两类参数。第一类是给定数值,会删除其中所有该数值;第二类是给定迭代器,会删除迭代器对应的元素——这样就只会删掉一个数字。
利用这些特点,我们可以用 upper_bound 找到第一把攻击力大于龙的生命值的剑,而上一把剑就是攻击力小于等于生命值的剑。然后用 delete 删除该剑的迭代器(不能是数值!)。
记龙的生命为 $h_i$,回复力为 $r_i$,则有两个限制:
- 攻击后龙的生命模 $r_i$ 余 $0$;
- 攻击后,龙的生命小于等于 $0$。
问题直接转化为 $n$ 对方程构成的方程组
不等式方程可以求出 $x$ 的下界。考虑如何求解同余方程。
$w_i,r_i$ 不一定互质,于是可能本身就无解。记 $(w_i,r_i)=g_i$,则必须满足 $g_i\mid h_i$,方程才有解。
满足有解的条件后,$w_i,h_i,r_i$ 同时除以 $g_i$,得到等价的方程 $w_i’x=h_i’\pmod {r_i’}$,此时 $(w_i’,r_i’)=1$,$w_i’$ 存在逆元,于是可以得到
这个方程就可以用 exCRT 了。
# 源代码
点击展开/折叠代码
1 | /*Lucky_Glass*/ |
THE END
Thanks for reading!
祈愿在风中渐渐冷冽
那一刻她眼底有华光泯灭
海潮呼啸着哽咽
想把不舍宣泄
所有分别都太决绝
回忆都太炽烈
最后一面何处去借
——《流光幻夜》By 司夏
\> Link [流光幻夜](http://music.163.com/song?id=1817417571&userid=303853271)-网易云