zoukankan      html  css  js  c++  java
  • Luogu P1390 公约数的和

    [ exttt{Description} ]

    给出 (n),求 (sumlimits_{i = 1}^nsumlimits_{j=i+1}^n gcd(i,j))

    [ exttt{Solution} ]

    注意到:

    [sumlimits_{i = 1}^nsumlimits_{j = i + 1}^n gcd(i, j) = frac{sumlimits_{i = 1}^nsumlimits_{j = 1}^n gcd(i, j) - sumlimits_{i = 1}^n gcd(i,i)}{2} = frac{sumlimits_{i = 1}^nsumlimits_{j = 1}^n gcd(i, j) - frac{n cdot (n + 1)}{2}}{2} ]

    于是问题转化为如何求出 (sumlimits_{i = 1}^nsumlimits_{j = 1}^n gcd(i, j))

    考虑枚举 (d = gcd(i, j)),则式子化为:

    [sumlimits_{d = 1}^n d cdot sumlimits_{i = 1}^nsumlimits_{j = 1}^n [gcd(i,j) = d] ]

    [sumlimits_{d = 1}^n d cdot sumlimits_{i = 1}^{frac{n}{d}}sumlimits_{j = 1}^{frac{n}{d}} [gcd(i,j) = 1] ]

    (g(n) = sumlimits_{i = 1}^nsumlimits_{j = 1}^n [gcd(i,j) = 1]),则式子化为:

    [sumlimits_{d = 1} ^ n d cdot g(frac{n}{d}) ]

    考虑化简 (g(n)),注意到:

    [varphi(n) = sumlimits_{i = 1}^n [gcd(n, i) = 1] ]

    则有:

    [g(n) = 2 cdot sumlimits_{i = 1}^n varphi(i) - 1 ]

    线性筛 (mathcal{O(n)}) 预处理出欧拉函数,再求一遍欧拉函数前缀和,即可 (mathcal{O(1)}) 计算 (g(n))

    至此 (sumlimits_{d = 1} ^ n d cdot g(frac{n}{d})) 已经可以 (mathcal{O(n)}) 计算,可以进一步用 " 数论分块 " 优化到 (O(sqrt n))

    [ exttt{Code} ]

    #include <cstdio>
    
    using namespace std;
    
    const int N = 2000100;
    
    int n;
    
    int m, prime[N], fac[N];
    int phi[N];
    long long S[N];
    
    void GetPrimes(int N) {
    	phi[1] = 1;
    	for (int i = 2; i <= N; i ++) {
    		if (!fac[i]) fac[i] = i, prime[++ m] = i, phi[i] = i - 1;
    		for (int j = 1; j <= m; j ++) {
    			if (prime[j] > fac[i] || prime[j] > N / i) break;
    			fac[i * prime[j]] = prime[j];
    			phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
    		}
    	}
    
    	for (int i = 1; i <= N; i ++)
    		S[i] = S[i - 1] + phi[i];
    }
    
    long long g(int n) {
    	return 2 * S[n] - 1;
    }
    
    int main() {
    	GetPrimes(2000000);
    
    	scanf("%d", &n);
    
    	long long ans = 0;
    	for (int x = 1, Nx; x <= n; x = Nx + 1) {
    		Nx = n / (n / x);
    		ans += 1ll * (x + Nx) * (Nx - x + 1) / 2 * g(n / x);
    	}
    
    	ans -= 1ll * n * (n + 1) / 2;
    	ans /= 2;
    
    	printf("%lld
    ", ans);
    
    	return 0;
    }
    

    [ exttt{Thanks} exttt{for} exttt{reading} ]

  • 相关阅读:
    引用kernel32.dll中的API来进行串口通讯
    vs2017 项目生成时不产生xml文件的方法
    session的处理机制
    用户未登录或Session超时时重定向到登录页,不那么简单
    VS C# debug文件夹中各文件的作用
    Tomcat(免安装版)的安装与配置【转】
    关于C#关闭窗体后,依旧有后台进程在运行的解决方法
    DatakeyNames和datakey
    ASP.NET页面生命周期描述
    比较C#中几种常见的复制字节数组方法的效率
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/13124835.html
Copyright © 2011-2022 走看看