欧拉函数的作用是,计算1~n 内与n互质的个数
那么我们可以把n拆成质因子相乘
为什么要拆成质因子相乘呢?
首先互质等价于没有公约数。
那么我们把1~n内与n有公约数的数踢掉,剩下的就是互质。那么问题来了,怎么判断有公约数了?
显然把n拆成质因子相乘那么假如与n有公约数的数,显然是要包含这些质因子,所以我们把1~n包含这些质因子的数全踢掉。那么该怎么知道了哪些数,包含这些质因子呢?
显然包含这些质因子的数,肯定是质因子的倍数,所以我们只要把是质因子的倍数的数踢掉,就等价于把,与n有公约数的数踢掉,等价于把与n非互质的数踢掉,剩下的就是互质的数。那么问题来了,那怎么统计互质的数呢?
例如60
可以拆成 2,2,3,5
那质因子就是 2,3,5 这三个数那60里面有多少个是2的倍数了的数了
显然有60*(1/2) = 30个
踢掉30个后,还剩下(1/2)*60个那么剩下的30个数里面,有多少个是3的倍数了
30*(1/3) = 10个 是3的倍数,踢掉后剩30*(2/3) = 20个那么多少个是5的倍数了
(1/5)*20 踢掉后剩(4/5)*20
那么显然是(1/2 * 2/3 * 4/5) * 60 只剩下这么多是互质的
下面来看看欧拉函数怎么写
int euler_phi(int n) {
int m = (int)sqrt(n + 0.5); //计算上界
int ans = n;
for(int i = 2; i <= m; i++) {
if(n % i == 0) { //如果当前这个数是n的质因子
ans = ans / i * (i-1);
while(n % i == 0) n /= i; //除去n的质因子
}
}
if(n > 1) ans = ans / n * (n-1); //还剩下最后一个质因子
return ans;
}
计算1~n中所有的数的欧拉phi函数值。并不要依次计算。可以用和筛选求素数非常类似的方法。
void phi_table(int n) {
for(int i = 2; i <= n; i++) { //初始化
phi[i] = 0;
}
phi[1] = 1;
for(int i = 2; i <= n; i++)
if(!phi[i]) //如果phi[i] == 0则表明i是素数
for(int j = i; j <= n; j += i) { //将所以i的倍数赋值
if(!phi[j]) phi[j] = j; //如果j没访问过则phi[j] = j
phi[j] = phi[j] / i * (i-1); //j的phi值 = j * (质因子i - 1) / (质因子)
}
}