莫比乌斯反演
狄利克雷卷积
f, g 为数论函数
, 即
性质
-
满足交换律
-
满足结合律,即
-
若 是积性函数,则 是积性函数(完全积性函数不满足此条性质)
常见卷积:
莫比乌斯反演
即
证明:
引理1:
引理2:
-
若 , 两边同时卷上
-
若 , 两边同时卷上
引理1,2 暴力带入狄利克雷卷积并利用积性函数的性质(两个积性函数卷起来仍是积性函数)即可证明
莫比乌斯反演 - 题目 - Daimayuan Online Judge
, 因此 , 线性筛求出
求 的过程可考虑每个因子对 的贡献,因此可以:
for (int d1 = 1; d1 <= n; d1++)
for (int d2 = 1; d1 *d2 <= n; d2++)
g[d1*d2] += f[d1] * mu[d2];
由调和级数,复杂度为
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int N = 1e6 + 10;
uint n;
uint pr[N/5], p[N], cnt, mu[N], f[N], g[N];
unsigned int A,B,C;
inline unsigned int rng61()
{
A ^= A << 16;
A ^= A >> 5;
A ^= A << 1;
unsigned int t = A;
A = B;
B = C;
C ^= t ^ A;
return C;
}
void get_primes(uint n)
{
p[1] = 1, mu[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!p[i])
{
p[i] = i;
mu[i] = -1;
pr[++cnt] = i;
}
for (int j = 1; j <= cnt && pr[j] <= n / i; j++)
{
p[i*pr[j]] = pr[j];
if (p[i] == pr[j])
{
mu[i*pr[j]] = 0;
break;
}
mu[i*pr[j]] = -mu[i];
}
}
}
int main()
{
scanf("%d%u%u%u", &n, &A, &B, &C);
for (int i = 1; i <= n; i++)
f[i] = rng61();
get_primes(n);
for (int d1 = 1; d1 <= n; d1++)
for (int d2 = 1; d1 *d2 <= n; d2++)
g[d1*d2] += f[d1] * mu[d2];
uint ans = 0;
for (int i = 1; i <= n; i++) ans ^= g[i];
printf("%u\n", ans);
return 0;
}
互质数对 - 题目 - Daimayuan Online Judge
组询问,每次给出 , 求 满足 的 的对数
因此求出 的前缀和,加上整除分块即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;
int pr[N/5], p[N], cnt, mu[N], s[N];
void get_primes(int n)
{
p[1] = mu[1] = s[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!p[i])
pr[++cnt] = i, p[i] = i, mu[i] = -1;
for (int j = 1; j <= cnt && pr[j] <= n / i; j++)
{
p[i*pr[j]] = pr[j];
if (p[i] == pr[j])
{
mu[i*pr[j]] = 0;
break;
}
mu[i*pr[j]] = -mu[i];
}
}
for (int i = 2; i <= n; i++)
s[i] = s[i-1] + mu[i];
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
get_primes(N - 10);
while(T--)
{
int n, m;
cin >> n >> m;
if (n > m) swap(n, m);
ll ans = 0;
for (int l = 1; l <= n; l++)
{
int r = min(n / (n / l), m / (m / l));
ans += (ll)(s[r] - s[l-1]) * (n / l) * (m / l);
l = r;
}
cout << ans << endl;
}
return 0;
}
gcd之和 - 题目 - Daimayuan Online Judge
跟上一题类似
形如: ,可用 找到 ,再用 带入得
=
本题中
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1e7 + 10;
int pr[N/5], p[N], cnt, phi[N];
ll s[N];
void get_primes(int n)
{
p[1] = phi[1] = s[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!p[i])
pr[++cnt] = i, p[i] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && pr[j] <= n / i; j++)
{
p[i*pr[j]] = pr[j];
if (p[i] == pr[j])
{
phi[i*pr[j]] = phi[i] * pr[j];
break;
}
phi[i*pr[j]] = phi[i] * (pr[j] - 1);
}
}
for (int i = 2; i <= n; i++)
s[i] = s[i-1] + phi[i];
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
get_primes(N - 10);
while(T--)
{
int n, m;
cin >> n >> m;
if (n > m) swap(n, m);
ll ans = 0;
for (int l = 1; l <= n; l++)
{
int r = min(n / (n / l), m / (m / l));
ans += (ll)(s[r] - s[l-1]) * (n / l) * (m / l);
l = r;
}
cout << ans << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!