前言
本文只是作者学习莫比乌斯反演后做的相关笔记,可能并不适合入门。
基础
莫比乌斯函数
设 (x=p_1^{alpha_1} imes p_2^{alpha_2} imes dots imes p_k^{alpha_k})。
则:
(mu(x)=egin{cases} 1&{x=1} \ 0&{alpha_i>1(1le ile k)} \ (-1)^k & ext{otherwise} end{cases})
一个基本性质
设 (S(n)=sumlimits_{d|n}mu(d))。
则 (S(n)=[n=1])。
证明略。
一个简单结论
第一个式子
证明:
第二个式子
证明:
令 (d'=frac{d}{n})。
值得注意的是,我们在做题中常用的是第二个式子。
例题
题意:求 (sumlimits_{ale xle b}sumlimits_{cle yle d}[gcd(x, y)=k])。
设 (S(a, b)=sumlimits_{1le xle a}sumlimits_{1le yle b}[gcd(x, y)=k])。
可以通过二维前缀和的方式转化问题,答案即为 (S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1))。
接下来有两种方法求解。
方法一:
设 (n=lfloorfrac{a}{k} floor),(m=lfloorfrac{b}{k} floor)。
方法二:
设 (F(n)=sumlimits_{x=1}^asumlimits_{y=1}^b[n|gcd(x,y)]=lfloorfrac{a}{n} floorlfloorfrac{b}{n} floor),(f(n)=sumlimits_{x=1}^asumlimits_{y=1}^b[gcd(x,y)=n])。
很显然有:(F(n)=sumlimits_{n|d}f(d))。
莫比乌斯反演得到:(f(n)=sumlimits_{n|d}mu(frac{d}{n})F(d))。
令 (d'=frac{d}{n}),(a'=frac{a}{n}),(b'=frac{b}{n})。
推式子:
然后整除分块即可。
代码:
#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d
", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
using namespace std;
typedef long long LL;
typedef pair <int, int> PII;
typedef pair <int, PII> PIII;
template <typename T>
inline T gi()
{
T f = 1, x = 0; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f * x;
}
const int INF = 0x3f3f3f3f, N = 50003, M = N << 1;
int T;
int mu[N], sum[N];
bool isprime[N];
int pri[N], tot;
inline void pre()
{
mu[1] = 1;
for (int i = 2; i <= 50000; i+=1)
{
if (!isprime[i]) pri[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && 1ll * i * pri[j] <= 50000; j+=1)
{
isprime[i * pri[j]] = true;
if (i % pri[j] == 0) break;
mu[i * pri[j]] = -mu[i];
}
}
for (int i = 1; i <= 50000; i+=1) sum[i] = sum[i - 1] + mu[i];
}
inline LL S(int a, int b, int k)
{
a /= k, b /= k;
int n = min(a, b);
LL ans = 0;
for (int l = 1, r; l <= n; l = r + 1)
{
r = min(n, min(a / (a / l), b / (b / l)));
ans = ans + 1ll * (sum[r] - sum[l - 1]) * (a / l) * (b / l);
}
return ans;
}
int main()
{
//File("");
pre();
T = gi <int> ();
while (T--)
{
int a = gi <int> (), b = gi <int> (),
c = gi <int> (), d = gi <int> (),
k = gi <int> ();
printf("%lld
", S(b, d, k) - S(a - 1, d, k)
- S(b, c - 1, k) + S(a - 1, c - 1, k));
}
return 0;
}