莫比乌斯反演
前置知识 & 重难点:数论分块
莫比乌斯函数
定义莫比乌斯函数\(\mu (x)\),如果\(x\)的某个质因数出现超过一次,则\(\mu(x)=0\),否则\(\mu(x)=(-1)^k\),其中\(k\)是\(n\)的本质不同的质因子个数。
形式化地,
其中\(p_i\)为不同的质数。
莫比乌斯函数是积性函数,并且有一个重要性质是:\(\sum_{d|n}\mu(d)=\cases{1,~~~~n=1\\0,~~~~n>1}\)
证明:\(\sum_{d|n}\mu(d)\)其实等价于\(\sum_{i=0}^{k}C_k^i(-1)^k\),相当于在\(k\)个质因数中选出\(i\)个,每一种\(i\)的答案的和。
莫比乌斯反演
设\(g(n)\)和\(f(n)\)是定义在非负整数集合上的两个函数,并且满足\(g(n)=\sum_{d|n}f(d)\),那么
证明:
莫比乌斯反演还有另外一种形式:如果\(f(n)=\sum_{n|d}g(d)\),那么
几种常见的莫比乌斯反演
上面的式子中 取\(f(n)=\mu(n)\),则有\(g(n)=\sum_{d|n}f(d)\),满足莫比乌斯反演的条件,可以进行反演,\(f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d})=\mu(n)\)
欧拉函数\(\phi(n)\)的一个性质是:\(n=\sum_{d|n}\phi(d)\)。带入\(f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d})\)得
\(\mu(n)\)是个积性函数,可以用线性筛预处理出来。
例题:
1.求\([1,n]\)和\([1,m]\)上互质的数的个数
然后数论分块求解就行哩
2.Crash的数字表格
这样就能\(O(nlnn)\)做了
但这样只能过70%,处理不了1e7的数据.注意到第二个和式中的\(\mu(d)d^2\)可以提出来用前缀和搞定,后面的式子可以\(O(1)\)算。记\(f(x,y)=\frac{x(x+1)y(y+1)}{4}, g(x,y)=\sum_{d=1}^{min(x,y)}\mu(d)d^2f(\lfloor\frac{x}{d}\rfloor,\lfloor\frac{y}{d}\rfloor)\),这个东西可以数论分块, 答案后面乘了个g也可以数论分块。
// Problem: P1829 [国家集训队]Crash的数字表格 / JZPTAB
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1829
// Memory Limit: 500 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 7;
#define ll long long
const ll md = 20101009;
int rd() {
int s = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') {s = s * 10 + c - '0'; c = getchar();}
return s * f;
}
int n, m, tot;
bool isp[maxn];
ll sumd[maxn], pri[maxn], mu[maxn];
void sieve() {
memset(isp, true, sizeof(isp));
isp[1] = false; mu[1] = 1;
for (int i = 2; i <= 10000000; i++) {
if (isp[i]) {
pri[++tot] = i;
mu[i] = -1;
}
for (int j = 1; j <= tot && i * pri[j] <= 10000000; j++) {
isp[i*pri[j]] = false;
if (i % pri[j] == 0) {
mu[i*pri[j]] = 0;
break;
}
mu[i*pri[j]] = -mu[i];
}
}
for (int i = 1; i <= 10000000; i++)
sumd[i] = (sumd[i-1] + 1ll * i * (mu[i] + md) % md * i % md) % md;
}
ll ksm(ll a, int b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % md;
a = a * a % md;
b >>= 1;
}
return res;
}
ll ans = 0, inv4 = ksm(4, md - 2), inv2 = ksm(2, md-2);
ll f(ll x, ll y) {
return (x * (x+1) % md * y % md * (y+1) % md * inv4 % md);
}
ll g(ll x, ll y) {
int t = min(x, y);
ll res = 0;
for (int l = 1, r; l <= t; l = r + 1) {
r = min(x / (x / l), y / (y / l));
res = (res + (sumd[r] - sumd[l-1]) * f(x/l, y/l) % md + md) % md;
}
return res;
}
ll h(ll x, ll y) {
ll res = 0;
int t = min(x, y);
for (int l = 1, r; l <= t; l = r + 1) {
r = min(x / (x / l), y / (y / l));
res = (res + g(x / l, y / l) * (l + r) % md * (r - l + 1) % md * inv2 % md + md) % md;
}
return res;
}
int main() {
n = rd(), m = rd();
sieve();
printf("%lld\n", h(n, m));
}