在今天的模拟赛中,部分同学由于对出现某个数在模 \(1000000007\) 意义下为 \(0\) 的情况不规范被 Hack。
Hack 原理:开始时有 \(2\) 个 \(1\),先都加到 \(1000000001\),然后一个一个加 \(8\) 次虽然加 \(7\) 次足以 Hack,这个时候如果对 \(1000000007\) 处理不好,可能后面都变成 \(0\)。
我的方案:考虑两个性质(按照题解):
- \(2\) 操作到 \(1000000007\) 的倍数(分子为 \(0\))只可能是 \(1000000007\),也就是说每个位置至多出现一次分子或分母为 \(0\)。
- 分母为 \(0\) 的上一步同样位置的 \(2\) 操作中一定分子为 \(0\),因为分母为 \(0\) 时必定出过 \(a_i=1000000007\)。(我可能给之前的同学解释错了,因为可能出现 \(3\) 操作使得分子分母为 \(0\) 的 \(2\) 操作之间夹着几个,但也无伤大雅,这里致以诚挚歉意)。
综上所述,考虑记录每个位置上一次的分子为 \(0\) 位置,维护一个指针指向当前更新到的点。遇到分子为 \(0\) 的值,停止维护,输出答案一定为 \(0\)。遇到分母为 \(0\),找到对应分子为 \(0\) 的位置,合并两个分数:将后者的分子赋给前者,后者置为 \(1\),这样保证后面的值都是对的。指针继续往下跳转,直到遇到下一个分子为 \(0\) 的数。
以 Hack 数据为例,最后几个数为 \(\frac{0}{1000000006},\frac{0}{1000000006},\frac{1}{0},\frac{1}{0}\cdots\),位置分别在 \(1,2,1,2\cdots\),扫到第一、二个数停止更新,输出 \(0\)。扫到第三个数,将第一个数变成 \(\frac{1}{1000000006}\),第三个数变为 \(1\),往下更新到第二个数处。扫到第四个数,同理更新,此时可以更新到第四个数。
附:数据,我的代码