扩大
缩小

【NOIP2014】解方程

最原始的思路(可以在 LG 上 AC 的)

  这题本身没有模数,但是我们可以造模数防止溢出。

  但是有一些数其实并不是方程的解,但它在模这个数下答案是 $0$。

  所以保险起见,我们对同一个数,求出它在两种不同模数下的答案,如果两者答案都是 $0$,那么判定这个数是解。

  从 $1$ 枚举到 $m$,对于每一个数都用 $O(n)$ 的复杂度验证是否有这个解,最后输出,复杂度 $O(n \cdot m)$,有一些常数。

  该做法在无常数优化情况下 LG 上最慢的点耗时 700ms 左右。

  注意,式子里有常数项,记得要加。

改进 1

  上面的做法在比较慢的机子只能拿到 $70$ 分,即使你用了很多常数优化。

  对于枚举到的每一个数,先判断它在方程中取模第一个数的值是否为 $0$,如果是就再判断使用第二个模数。

改进 2

  一个一元 $n$ 次方程的不同解数量不超过 $n$。

  所以只要找到 $n$ 个解就可以直接退出枚举。

改进 3

  我们把第一个模数 $p_1$ 缩小。具体原因如下:

  如果数 $a$ 在 $[1,p_1]$ 中,且把 $a$ 代入值不为 $0$,那么 $a+p_1,a+2p_1,...$ 都不是方程的解,因为这些数代入方程对 $p_1$ 取模的值肯定不是 $0$。

  所以我们可以选定一个合适的 $p_1$,找到在该模数下所有的解,假设某一个解为 $k$。

  那我们把 $k$,$k+p_1$,$k+2p_1$,$...$ 都放到第二个模数来验证,得到所有的解。

  当然所有数能够验证的前提是不超过 $m$。

  需要注意的是,这些解并不一定是有序的,需要排序。


还有最后一个问题:这个 $p_1$ 该取多大呢?

  现在整个程序在程序中分成了三块:

  ① 读入:$O(n \times |a_i|)$,这里看作 $1e7$;

  ② 从 $1$ 枚举到 $p_1$ 找方程模 $p_1$ 下代入的值为 $0$ 的解,复杂度为 $O(n \times p_1)$;

  ③ 找从第二步中筛出的解按照优化 3 的方式再次验证,复杂度最大为 $O(n^2 \times \frac{m}{p_1})$(在没有假解的情况下)。

  假设 $n,m$ 都取到最大,而且我们希望两项都不超过 $1e7$(常数问题)。

  那么得到的是 $10^3 \le p_1 \le 10^5$。

  但是 $p$ 不要往小取,因为你会无缘无故地在第一轮筛出很多假的解,拉低效率。

  所以如果想要质数,并且比较快,那么可以用 $100003$ 之类的数。

posted @ 2020-04-03 18:58  HoshizoraZ  阅读(238)  评论(0)    收藏  举报