【 欧拉函数 】GCD - Extreme (II)

我只是一个虾纸丫 提交于 2019-11-27 05:28:27

 

  • Step1 Problem

原题 给一个数n,输出sigma(gcd(i,j))1<=i<=j,i<=j<=n

  • Step2 Ideas:

假设a、b(a<b)互质,那么gcd(a,b)=1,这样当i循环到a、j循环到b时就会向结果中+1,而i循环到2*a、j循环到2*b时就会向结果中+2(gcd(2*a,2*b)=2)...循环到k*a和k*b时就会向结果中+k。这样实际上引起结果变化的根源就在于各对互质的数,当i、j循环到他们自身或者自身的倍数时就会引起结果的改变,那么我们不妨先将每对互质的数对结果的贡献值算出来,最后将各对互质的数对结果的贡献累加起来就可以了。

    假设和b互质的数有n个,也就是n对(?,b)(?和b互质),那么在i、j循环到?、b时结果会增加n,循环到(2*?,2*b)时结果就会增加2*n...当i、j循环到k*?、k*b时结果就会增加k*n。那么我们不妨用a[i]记录各种k、b在满足k*b=i时会增加多少结果,也就是说a[i]记录的是小于i的每个数与i最大公约数之和,那么最后我们要输出的就是a[2]+a[3]+...+a[N]。

    至于找和b互质的数,就是计算b的欧拉函数的值,然后暴力循环k,并修改对应的a[k*b]即可,整体的复杂度是O(N*logN)的。

    欧拉公式的延伸小于n 与n互质的数的和 是euler(n)*n/2

思路来源

  • Step3 Code:
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<bitset>
 6 #include<cassert>
 7 #include<cctype>
 8 #include<math.h>
 9 #include<cstdlib>
10 #include<ctime>
11 #include<deque>
12 #include<iomanip>
13 #include<list>
14 #include<map>
15 #include<queue>
16 #include<set>
17 #include<stack>
18 #include<vector>
19 #define lt k<<1
20 #define rt k<<1|1
21 #define lowbit(x) x&(-x)
22 #define lson l,mid,lt
23 #define rson mid+1,r,rt
24 using namespace std;
25 typedef long long  ll;
26 typedef long double ld;
27 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
28 #define mem(a, b) memset(a, b, sizeof(a))
29 //#define int ll
30 const double pi = acos(-1.0);
31 const double eps = 1e-6;
32 const double C = 0.57721566490153286060651209;
33 const ll mod = 3e7;
34 const int inf = 0x3f3f3f3f;
35 const ll INF = 0x3f3f3f3f3f3f3f3f;
36 const int maxn = 4e6 + 5;
37 int phi[maxn];
38 ll a[maxn];
39 
40 void prep() {
41     mem(a, 0);
42     for(int i = 1; i <= 4e6; i++) phi[i] = i;
43     for(int i = 2; i <= 4e6; i++) {
44         if(phi[i] == i) {
45             for(int j = i; j <= 4e6; j += i) {
46                 phi[j] = phi[j] / i * (i - 1);
47             }
48         }
49         for(int j = 1; j * i <= 4e6; j++) a[j * i] += j * phi[i];
50     }
51     for(int i = 1; i <= 4e6; i++) a[i] += a[i - 1];
52 }
53 
54 int main() {
55     prep();
56     int n;
57     while(cin >> n && n) {
58         cout << a[n] << endl;
59     }
60     return 0;
61 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!