BZOJ2818:GCD 题解

思路

乍一看其实可以跟欧拉函数扯上关系。我们要求的是\(gcd(x,y) \in Prime, x, y \leq N\)的有序对个数。我们设那个质数为\(s\),则可以化为:

\[ x = sa, y = sb \\ gcd(a, b) = 1 \]

嗯,看到欧拉函数的影子了。对于每一个质数\(s\),它对答案的贡献是:

\[ 2 * \sum_{ 1 \leq i \leq \lfloor \frac{n}{s} \rfloor } \phi(i) – 1 \]

我来解释一下:因为\(x,y \leq n\),所以\(sa \leq n\),\(sb \leq n\),得:

\[ a,b \leq \frac{n}{s} \]

所以会有这么多对,考虑这个是有序对,所以乘上二,再删除掉\((i,i)\)这样的有序对重复即可得到答案。注意,可以用前缀和欧拉函数值来进行优化。

代码

// BZ2818.cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX_N = 10000005;
ll n, phi[MAX_N];
bool isPrime[MAX_N];
int main()
{
    //memset(isPrime, true, sizeof(isPrime));
    scanf("%lld", &n);
    for (int i = 2; i <= n; i++)
        phi[i] = i;
    for (int i = 2; i <= n; i++)
        if (!isPrime[i])
            for (int j = i; j <= n; j += i)
            {
                if (j != i)
                    isPrime[j] = true;
                phi[j] = phi[j] / i * (i - 1);
            }
    phi[1] = 1;
    for (int i = 2; i <= n; i++)
        phi[i] += phi[i - 1];
    long long ans = 0;
    for (int i = 2; i <= n; i++)
        if (!isPrime[i])
            ans += 2 * phi[n / i] - 1;
    printf("%lld", ans);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *