洛谷:P3601:签到题


洛谷:P3601:签到题

题目

P3601:签到题

分析

有一个著名的“欧拉公式”,用来计算小于等于n的正整数中与n互质的数的个数,记作\(\varphi(n)\)。计算公式为:对于一个正整数n,若其质因数分解为\(n=p_1^{k_1}p_2^{k_2}...p_m^{k_m}\),则:\(\varphi(n)=n\prod_{i=1}^m(1-\frac{1}{p_i})\)。当然本题要计算的,是与n不互质的数的个数,所以是\(n-\varphi(n)\)

准备工作一:欧拉筛计算到\(\sqrt r\)的质数

这是一个常规的算法。其详细的解法可以参考P3383:线性筛素数

根据题意,\(r\le 10^{12}\),所以\(\sqrt r\le 10^6\)

计算\(\varphi(n)\)

我们用两个数组来保存中间数据。一个是A[i],存储某个数i\(\varphi(i)\)。为了避免计算\(\frac{1}{p_i}\)可能出现的很小很小的数字,我们将其变形为:\((p_i-1) / p_i\)

考虑更大的质因子

我们第一步准备工作中,只算到了\(\sqrt r\)的质因子,但可能还有比这大的质因子——但只可能有一个。我们还要考虑这个情况。我们用一个辅助数组B[i]来进行处理。方法是:

  1. 初始时,A[i]=B[i]=i,也就是各自等于要计算\(\varphi(i)\)的那个i
  2. 每次用一个\(p_i\)计算A[i]的时候,不断将B[i]中对应的这个质因子去掉。
  3. 如果最后B[i]==1,说明这个数字被之前的质因子分解完毕了。否则,还要计算一次,此时的质因子就是B[i]

其他技巧

由于lr本身值很大,但r-l(区间)较小,所以我们可以进行一个“偏移”映射,也就是\(l\Rightarrow 0, r\Rightarrow (r-l)\)。这样就避免了开一个巨大但十分稀疏的数组。

答案

Solution

思考

代码的45行,用B[i]^1来判断B[i]是不是等于1,这是一种古老的做法:因为在C时代,普遍认为这样的异或运算比纯比较运算要快一些。

上一篇 下一篇