1. 题目

1. 题目

美国高中数学竞赛中的一道数论题目:

整数 $n\geq 2$。如果 $n$ 是质数,则 $S(n)=n$。如果 $n$ 不是质数,$S(n)$ 是所有因子 $d$ 的和,其中 $1

求比 $2019$ 小的全部循环质数的数量。

2. 题解

首先我们假设有一个循环质数 $n$,那么 $S(n)$ 必然不是质数。因为如果 $S(n)$ 是质数,那么 $S(S(n))=S(n)$,因此 $n$ 不是循环质数。

接着我们考虑,如果 $S(n)$ 是合数,那么 $S(S(n))$ 必然不是质数。因为 $S(n)$ 除了 $n$ 以外,还有其他因子,这些因子在 $S(S(n))$ 中都会被计算一遍,因此 $S(S(n))$ 也是合数。

所以,如果一个数 $n$ 满足 $S(n)$ 是合数,那么 $n$ 不可能是循环质数。

然后我们考虑,如果 $S(n)$ 中不包含 $2$,那么 $S(S(n))$ 必然是偶数。因为 $S(n)$ 中不包含 $2$,那么 $S(S(n))$ 就相当于计算了 $S(n)$ 的偶数倍,因此 $S(S(n))$ 是偶数。

因此,如果一个数 $n$ 满足 $S(n)$ 中不包含 $2$,那么 $n$ 不可能是循环质数。

综上所述,如果一个数 $n$ 是循环质数,那么 $S(n)$ 是质数,且 $S(n)$ 中包含 $2$。

然后我们可以枚举每一个 $n$,判断 $S(n)$ 是否为质数,且 $S(n)$ 中是否包含 $2$。如果是,我们就继续计算 $S(S(n))$,直到得到一个合数或者一个已经计算过的数(即出现循环)为止。如果最终得到的是一个质数,那么 $n$ 就是循环质数。

3. 代码

下面是判断一个数是否为质数的函数:

bool is_prime(int n) {

if (n<2) return false;

for (int i=2; i*i<=n; i++) {

if (n%i==0) return false;

}

return true;

}

下面是计算 $S(n)$ 的函数:

int s(int n) {

int ans=1;

for (int i=2; i

if (n%i==0) ans+=i;

}

return ans;

}

最后是判断一个数是否为循环质数的函数:

bool is_circular(int n) {

set visited;

visited.insert(n);

int sn=s(n);

while (true) {

if (!is_prime(sn) || sn==n) return false;

if (visited.find(sn)!=visited.end()) return true;

visited.insert(sn);

sn=s(sn);

}

}

对于 $n=2$,$S(n)=1$,并不满足 $S(n)$ 包含 $2$ 的条件,因此不能算作循环质数。

对于 $2

代码如下:

int ans=0;

for (int n=3; n<2019; n++) {

if (n%2==0) continue;

int sn=s(n);

if (sn%2==0) continue;

if (!is_prime(sn)) continue;

if (!is_circular(n)) continue;

ans++;

}

cout << ans << endl;

答案为 $58$。

4. 总结

这道题需要一些数论基础知识,包括质数、因子等。另外,需要注意一些细节,如判断循环条件时需要用 set 等数据结构保存已经计算过的数,避免重复计算。

如果时间允许,我们可以将 is_circular 函数改为莫比乌斯函数,以加速计算过程。具体来说,如果 $n$ 是循环质数,那么它的所有因子乘积的莫比乌斯函数值为 $-1$。因此,可以先预处理出所有的莫比乌斯函数值,然后根据这个值来判断循环质数。

总之,这道题不算非常难,但需要一些数论基础和编程技巧。希望读者能够在解题中加强自己的数论和编程能力。


文章TAG:美国高中数学竞赛题  美国高中数学竞赛的数论题改写题目  
下一篇