【莫比乌斯反演】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;
}
发表评论