• Luogu P2568 GCD 题解


    题目

    分类讨论

    对于满足要求的数对(x,y),有两种情况:

    A:x、y 中有一个是质数p,另一个数是p的倍数,此时gcd(x, y)显然为p,满足要求

    B:x = p·k1, y = p·k2, p为质数,且k1, k2互质,gcd(x, y)也为质数p

    方案计算

    先用素数线性筛和欧拉函数的递推式预处理出1——n的数中的质数和每个数的欧拉函数

    对于情况
    A:枚举每个质数,注意(x,y)和(y, x)不同,因此要乘上 2,但当x、y相同时只能算一种,因此乘上2再减去1

    B:枚举1——n的每个数 i,x = p·k1, y = p·k2(p为质数),以i为k1的情况数有:(满足p·k1<=n且p<=i的质数p的个数) * (i之前与i互质的数的个数(欧拉函数)),注意也要乘上2

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e7 + 5;
    int n, tot, k[N], p[N], a[N], s[N];
    long long res;
    void Pre_work () {
    	for (int i = 2; i <= n; ++i) {
    		if (!k[i]) p[++tot] = i, a[i] = i - 1;   //如果是质数,与 i 互质的数的个数为 i-1 
    		for (int j = 1; j <= tot, p[j] * i <= n; ++j) {
    			k[p[j] * i] = 1, a[p[j] * i] = a[i] * (p[j] - (i % p[j] != 0));  //套用欧拉函数递推式 
    			if (i % p[j] == 0) break;
    		}
    	}
    	for (int i = 2; i <= n; ++i) s[i] = s[i - 1] + (k[i] == 0);     //预处理质数个数的前缀和 
    }
    int main() {
    	scanf ("%d", &n);
    	Pre_work ();
    	for (int i = 2; i <= n; ++i) res += s[n / i] * (a[i] - 1) << 1;   //情况 B  
    	for (int i = 1; i <= tot and p[i] <= n; ++i) res += ((n / p[i]) << 1) - 1; //情况 A 
    	printf ("%lld
    ", res);
    	return 0;
    } 
    
  • 相关阅读:
    委托使用不当导致内存变大
    Reactive Extension
    WPF TextBox输入显示提示
    Reactive Extensions 初识
    WPF 验证
    SPOJ 1487. Query on a tree III
    HDU3966 Aragorn's Story
    SPOJ 2939. Query on a tree V
    SPOJ 913. Query on a tree II
    SPOJ2666. Query on a tree IV
  • 原文地址:https://www.cnblogs.com/whx666/p/11923723.html
Copyright © 2020-2023  润新知