zoukankan      html  css  js  c++  java
  • 【 欧拉函数 】GCD

    • 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 }
  • 相关阅读:
    New Skateboard
    Mike and strings
    C语言异或运算在程序设计中的妙用
    快速排序
    贪心算法
    快速排序过程分析
    深度搜索C语言伪代码
    matlab 中“newff” 函数的参数设置
    一维小波分解与去噪重构
    matlab绘图(详细)(全面)
  • 原文地址:https://www.cnblogs.com/zyysyang/p/11347278.html
Copyright © 2011-2022 走看看