其实这道题的主体并不难,主要是细节很多
我们可以把题目分成界限分明的两部分,第一部分,屠每条龙所用的剑只和当前拥有的剑有关。于是可以单独开一个数据结构按题目维护。
另一部分找到最小攻击次数,可以化作以下式子:
\(atk \cdot x \equiv a[i](mod\;p[i])\)
这时我们便能明白题目中所有宝剑攻击力均为1的部分分的含义。因为此时就是标准的exkmp模板。
所以我们要解决的就是x带系数的一元同余方程组。
思考excrt
的步骤:
设 \(m = gcd(p_1,p_2...,p_{i-1})\),x满足前i-1个同余方程,则满足前i个方程的解必须为 \(x+tm\) 的形式(t为常数)
那么实际上方程为:\(x+tm \equiv a_i(mod\;p_i)\)
既然x为定值,那么可以把x移动到右边,使方程变为\(tm \equiv a_i-x(mod\;p_i)\)
于是可以化为:\(tm+pa_i=b_i-x\)。即一个以t,p为未知数的二元一次不定方程。然后用扩展欧几里得求解。
发现实际上,当x带系数 atk
时最后一个不定方程可以转化为:
\(tm\cdot atk+pai=b_i-atk\cdot x\)
其实也就是把 \(x+tm\)变成了\(atk(x+tm)\)。
这同样是一个同余方程,所以同样可以用扩欧求解
但要注意几个小问题:
-
不同于一般的
excrt
第一个方程直接赋值解决,这里第一个方程也需要做一次扩欧,所以和后面一起循环就好。 -
与
excrt
模板一样,在进行乘法时,也需要__int128
或龟速乘帮忙。 -
注意题目中必须要砍到龙血量为非正数才能杀死龙,所以当最终答案不足以杀死血最厚的龙时需要不断地加上所有攻击的最小公倍数(为什么是最小公倍数?原因和设m的原因相同)。
-
为什么
excrt
和atk
要用代码块?因为不这样会有烦人的语法检查