欧拉函数
在N=p1^a1*p2^a2*...*pm^am中p是质因数,a是指数;如 24=2^3*3^1;



即 Q(N)=N*(1-1/p1)*(1-1/p2)*...*(1-1/pm);

这里如果用欧几里得算法(即辗转相除法)gcd(),从1开始一个一个数与N算,光是O(100*2*1e9)就会超时;
所以这里要用到欧拉函数
《证明》
这里要用到容斥原理


如何求1~N中,与N互质的个数?
最朴实的做法是:N - 与N有公约数的数的个数
在1~N 中 p1的倍数个数是N/p1(一定是整除才行),同理 pi的倍数个数是N/pi;
第一步:
从1~N中去掉p1,p2...pk的所有倍数:N-N/p1-N/p2-...N/pk;
但是发现有些数即是pi的倍数也是pj的倍数,但是这些数我本来只要减去1次,但是上面的减去了2次
所有
第二步:
从1~N中加上是pi*pj的倍数的个数:N-N/p1-N/p2-...N/pk + N/p1*p2+N/p1*p3+....+N/pk-1*pk;
但是又发现有些数 即是pi的倍数 也是pj的倍数,也是pk的倍数;但在+N/pi*pj+N/pi*pk+N/pj*pk中我加了3次
但是这些数我本来才上面-N/pi-N/pj-N/pk
相当于这些数即没加也每减
所以:
第三步:
从1~N中减去是pi*pj*pk的倍数的个数:
................
按照这个规则+二项式展开:Q(N)=N*(1-1/p1)*(1-1/p2)*....*(1-1/pm)
《代码》
1 #include <iostream>
2 #include <algorithm>
3 #include <cstring>
4 using namespace std;
5 int main()
6 {
7 int n;
8 cin >> n;
9 while (n--)
10 {
11 int num, ans;
12 cin >> num;
13 ans = num;
14 for (int i = 2; i <= num / i; i++)
15 {
16 if (num % i == 0)
17 {
18 while (num % i == 0)
19 num /= i;
//注意这里还是挺有讲究的
//不能写成ans=ans*(i-1)/i,因为可能i很大,ans*(i-1)之后就爆int了
20 ans = ans / i * (i - 1);
21 }
22 }
23 if (num > 1)
24 ans = ans / num * (num - 1);
25 cout << ans << endl;
26 }
27 return 0;
28 }
《筛法求1~n中的欧拉函数之和》

普通做法循环n个数,对于每个数求分解质因数,总时间复杂度O(n^2),超时
利用线性筛的思想,O(n)时间内可解出:
1 #include <iostream>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5 const int N = 1e6 + 10;
6 typedef long long LL;
7 //保存每一个数的欧拉函数
8 int phi[N], primes[N], cnt = 0;
9 bool st[N];
10 LL get_eulers(int n)
11 {
12 memset(st, false, sizeof(st));
13 phi[1] = 1;
14 for (int i = 2; i <= n; i++)
15 {
16 if (!st[i])
17 {
18 primes[cnt++] = i;
19 //下面都是对合数的处理,这里处理质数
20 phi[i] = i - 1; //==i*(1-1/i)
21 }
22 for (int j = 0; primes[j] <= n / i; j++)
23 {
24 st[primes[j] * i] = true;
25 if (i % primes[j] == 0)
26 {
27 //能进这里说明i是个合数,primes[j]是其最小质因数
28 // Q(i)=i*(1-1/p1)*(1-1/p2)*...*(1-1/pk);其中一定包含(1-1/primes[j]);
29 // Q(primes[j])=primes[j]*(1-1/primes[j]);
30 // Q(i*primes[j])=i*primes[j]*(1-1/p1)*(1-1/p2)*...*(1-1/pk);
31 // Q(i*primes[j])==Q(i)*primes[j];
32 phi[i * primes[j]] = phi[i] * primes[j];
33 break;
34 }
35 //没进入上面的语句说明primes[j]不是i的质因数
36 // Q(i)=i*(1-1/p1)*(1-1/p2)*...*(1-1/pk);其中一定不包含(1-1/primes[j]);
37 // Q(primes[j])=primes[j]*(1-1/primes[j]);
38 // Q(i*primes[j])=i*primes[j]*(1-1/p1)*(1-1/p2)*...*(1-1/pk);其中一定包含(1-1/primes[j]);
39 // Q(i*primes[j])==Q(i)*Q(primes[j]);
40 phi[i * primes[j]] = phi[i] *(primes[j]-1);
41 }
42 }
43 LL res = 0;
44 for (int i = 1; i <= n; i++)
45 res += phi[i];
46 return res;
47 }
48 int main()
49 {
50 int n;
51 cin >> n;
52 cout << get_eulers(n);
53 return 0;
54 }

浙公网安备 33010602011771号