欧拉函数

 

 在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 }

 

posted @ 2022-08-02 23:24  次林梦叶  阅读(81)  评论(0)    收藏  举报