【莫比乌斯反演】acwing220

就当复习莫比乌斯反演了吧

传送门

解法:莫比乌斯反演

f(d) = [gcd = d],表示gcd为d的数的对数的个数

g(p) = \sum_{p|d}f(d),表示gcd为p的倍数的数对的个数,其中p代表的质数

易知g(p) = \lfloor n / p \rfloor \lfloor n / p \rfloor ,因为如果两个数都是p的倍数,那他们的gcd也一定是p的倍数。小于n的p的倍数的个数就是\lfloor n / p \rfloor,由于需要的是两个组成一个数对,所以乘法原理相乘一下。

g(p) = \sum_{p|d}f(d) = \lfloor n / p \rfloor \lfloor n / p \rfloor里的g是好求的,而我们需要的是f函数和的值,可以用莫比乌斯反演,将计数关系交换。

反演以后f(p) = \sum_{p|d} \mu(d/p) g(d)

将函数g展开即f(p) = \sum_{p|d} \mu(d/p) \lfloor n / p \rfloor \lfloor n / p \rfloor

其中mu为莫比乌斯函数,这一项可以在线筛的时候求和,后面下取整除法只有2\sqrt{n}种取法,所以可以分块计算。

计算一个质数的f函数复杂度O(\sqrt{N}),题目给出的N为1e7,根据素数定理,小于N的质数个数约为N / logN个,也就是大概3e5个。一个一个算复杂度大概3e8可以接受

总复杂度O(N / logN * \sqrt{n} )

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 233;
int primes[maxn], mu[maxn], sum[maxn], cnt;
bool st[maxn];
void get_primes(int n)
{
    mu[1] = 1; sum[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!st[i]) primes[cnt++] = i, mu[i] = -1;
        sum[i] = sum[i - 1] + mu[i];
        for(int j = 0; j < cnt &&  i * primes[j] <= n; j++)
        {
            st[primes[j] * i] = 1;
            if(i % primes[j] == 0)
            {
                mu[primes[j] * i] = 0;
                break;
            }
            else mu[primes[j] * i] = -mu[i];
        }
    }
}
int main()
{
    get_primes(10000000);
    int n; cin >> n;
    ll ans = 0;
    for(int j = 0; j < cnt && primes[j] <= n; j++)
    {
        int a = n / primes[j], c = 0;
        for(int i = 1; i <= a; i = c + 1)
        {
            c = n / (n / i);
            ll b = i * primes[j];
            ll t = (n / b) * (n / b);
            ans += (ll)(sum[c] - sum[i - 1]) * t;
        }
    }
    cout<<ans;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注