• P2568 GCD


    题意描述:

    洛谷

    给你一个 \(n\)\(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{n} [gcd(i,j)为质数]\)

    数据范围:\(n\leq 10^7\)

    sloution

    首先我们很容易想出来怎么打暴力,我们可以对于每个 \(i\)\(j\) 都求一遍他们的 \(gcd\) 最后累计一下 \(gcd\) 为质数的就完成了。

    可是这样得神仙时间复杂度 为 \(O(n^2)\), 对于这道题,我们肯定会 TLE。

    我们就只能苦逼的想正解QAQ

    然后就开始我们的推柿子时间QAQ

    我们考虑这个柿子: \(gcd(x,y) = p\)

    那么这个柿子可以写成 \(gcd(x' * p , y' * p) = p\)

    提出 \(p\) 来就可以变成 \(gcd(x',y') = 1; x' = x / p ,y' = y / p\);

    我们有一个推论就是:

    \(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{n} [gcd(i,j) = 1]\) 不就相当于 \(\displaystyle 2 \times \sum_{i=1}^{N} \varphi(i) -1\)

    证明:
    因为 \(gcd(i,j) = gcd(j,i)\), 所以 \(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{n} [gcd(i,j) == 1] = (2\times \sum_{i=1}^{n}\sum_{j=1}^{i} [gcd(i,j) == 1])-1\), (\(-1\) 是因为 \(i = j = 1\) 的时候算了两次)。
    \(\displaystyle\sum_{j=1}^{i} [gcd(i,j) == 1]\) 等价于 \(1-i\) 内与 \(i\) 互质的个数,也就是 \(\varphi(i)\)
    那么我们的式子可以写成: \(2\times \displaystyle\sum_{i=1}^{n} \varphi(i) - 1\)

    因此对于每个 \(p\),他的贡献就是 \(\displaystyle 2\times \sum_{i=1}^{N\over p} \varphi(i) -1\).

    那么有多少个这样的 \(p\) 呢???

    其实 \(p\) 就是 \(N\) 以内的质数,对于每个 \(p\),求一下他的贡献,在相加,不就可以轻松AC了吗QAQ。。。

    那么最后的总柿子就是

    \(\displaystyle\sum_{p} (2\times \sum_{i=1}^{N\over p} \varphi(i))-1 ( p 是1~n的质数)\)

    优化: 我们再求 \(p\) 的贡献时,不必要一个个的去求欧拉函数的值,我们可以考虑维护
    一下前缀和。这样就会减少不少时间了...

    最后附上我的代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 1e7+10;
    long long n,ans = 0,cnt;
    long long prime[N] ,phi[N], tot[N];
    bool check[N];
    void calc(int n){//边进行欧拉筛,边求欧拉函数
         memset(check,-1,sizeof(check));
         phi[1] = 1;
         for(int i = 2; i <= n; i++){
         	if(check[i]){
         		phi[i] = i-1;
         		prime[++cnt] = i;
         	}
         	for(int  j = 1; j <= cnt; j++){
         		if(i * prime[j] > n) break;
         		check[i*prime[j]] = 0;
         		if(i % prime[j] == 0){
         			phi[i*prime[j]] = phi[i] * prime[j];
         			break;
         		}
         		else{/积性函数性质
         			phi[i*prime[j]] = phi[i] * phi[prime[j]];
         		}
         	}
         }
         for(int i = 1; i <= n; i++) tot[i] = tot[i-1] + phi[i];//前缀和
    }
    int main(){
        scanf("%d",&n);
        calc(n);
        for(int i = 1; i <= cnt; i++){//枚举每个p
        	ans += 2 * tot[n/prime[i]] - 1;//求p的贡献
        }
        printf("%d\n",ans)
        return 0;
    }
    
  • 相关阅读:
    算法竞赛入门经典训练指南
    git保护--git分支创建
    解决多个iframe嵌套而造成的多个滚动条问题
    css如何让div元素铺满整个屏幕
    第一个用python3写的爬虫小例子
    用JS获取当前页面的URL以及截取其中的字段
    css处理超出文本截断问题的两种情况(多行或者单行)
    约数的个数
    成绩排序
    八进制
  • 原文地址:https://www.cnblogs.com/genshy/p/13300950.html
Copyright © 2020-2023  润新知