莫比乌斯反演例题解析

传送门
题目描述

给定整数N,求1<=x,y<=N(N<=10^7)且Gcd(x,y)为素数的
数对(x,y)有多少对.

输入

一个整数N

输出

如题

样例输入

4

样例输出

4
解题思路:
这个题目出来可以用欧拉函数来解答之外,点击此处 这是欧拉函数解这道题的思路
那么我们还可以用莫比乌斯反演来做,首先介绍一下莫比乌斯反演的公式:

F(n)=d|nf(d) f(n)=d|nF(nd)miu(d)(1)

其实还可以这么写:
F(n)=n|df(d) f(n)=n|dmiu(dn)F(d)(2)

在这道题里面就可以这么设了,那么我们现在可以给两个f函数赋值了:
f(d)GCD(x,y)==d(1<=x,y<=n)

F(d)d|GCD(x,y)(1<=x,y<=n)

那么我们可以写出
F(d)=ndnd(3)

所以根据式子(2)和(3)可以知道
f(n)=n|dmiu(dn)ndnd

又因为 GCD(x,y) 是素数,那么我们可以枚举区间[1,n]的每个素数(素因子分解可以实现)

ans=pn(dnmiu(d)npdnpd)p

然后再YY一下就可以搞定了。。。
上代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>

using namespace std;
typedef long long LL;
const int MAXN = 1e7+5;
bool prime[MAXN];
int p[MAXN];
int mu[MAXN];
int phi[MAXN];
int k;
///mu函数
void Init()
{
    k = 0;
    memset(prime, 0, sizeof(prime));
    mu[1] = 1;
    for(int i=2; i<MAXN; i++)
    {
        if(!prime[i])
        {
            p[k++] = i;
            mu[i] = -1;
            phi[i] = 1;
        }
        for(int j=0; j<k&&i*p[j]<MAXN; j++)
        {
            prime[i*p[j]] = 1;
            if(i%p[j] == 0)
            {
                mu[i*p[j]] = 0;
                phi[i*p[j]] = mu[i];//p[j] * phi[i];
                break;
            }
            else
            {
                mu[i*p[j]] = -mu[i];
                //phi[i*p[j]] = (p[j]-1) * phi[i];
                phi[i*p[j]] = mu[i] - phi[i];
            }
        }
    }
}
int sum[MAXN];
void get_sum()
{
    sum[0] = 0;
    for(int i=1; i<MAXN; i++)
        sum[i] = sum[i-1]+phi[i];
}
int main()
{
    Init();
    get_sum();
    LL n;
    scanf("%lld",&n);
    LL ans = 0;
    for(int i=1,last; i<=n; i=last+1)
    {
        last = n/(n/i);
        ans += (n/i)*(n/i)*(sum[last]-sum[i-1]);
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(莫比乌斯反演)