莫比乌斯函数与莫比乌斯反演
https://www.luogu.com/article/vycu5sds
https://www.cnblogs.com/heyuhhh/p/11231502.html
https://www.luogu.com/article/qkowpfcc
前置
数论分块
简介
数论分块可以快速计算一些含有除法向下取整的和式。它主要运用富比尼定理,将
引理
证明:
形式一
求:
我们知道有许多
例题:UVA11526
海螺,海诺,唔,这个小海螺你要收好咯,能听到我隐藏版的歌声唷
#include <bits/stdc++.h> #define int long long using namespace std; int T,n; int H(int x){ int res = 0,l = 1,r; while(l <= x){ r = x / (x / l); res += (r - l + 1) * (x / l); l = r + 1; } return res; } signed main(){ scanf("%lld",&T);while(T --){ scanf("%lld",&n); printf("%lld\n",H(n)); } return 0; }
形式二
给定
推导:原式
注意处理一下边界的细节问题。
例题 P2261 [CQOI2007] 余数求和
要藏好我的鱼尾巴,别被人类发现啦!
#include <bits/stdc++.h> #define int long long using namespace std; int n,k; int H(){ int res = 0,l = 1,r; while(l <= min(n,k)){ r = k / (k / l); if(r > n) res += (l + n) * (n - l + 1) / 2 * (k / l); else res += (l + r) * (r - l + 1) / 2 * (k / l); l = r + 1; } return res; } signed main(){ scanf("%lld%lld",&n,&k); printf("%lld",n * k - H()); return 0; }
形式三
求:
对前半段的函数维护一个前缀和,再用整除分块处理后半段,两段相乘即可。
习题
P3935 Calculating
推导:
别害怕,黑夜只是白天的前奏
#include <bits/stdc++.h> #define int long long #define MOD 998244353 using namespace std; int H(int n){ int res = 0,l = 1,r; while(l <= n){ r = n / (n / l); res += (r - l + 1) * (n / l); res %= MOD; l = r + 1; } return res; } signed main(){ int l,r;scanf("%lld%lld",&l,&r); printf("%lld",(H(r) + MOD - H(l - 1)) % MOD); return 0; }
P2260 [清华集训2012] 模积和
注意题目要求
我们依旧是分块去求,只不过我们要找的块是 min(n / (n / l),m / (m / l))
即可。关于
关于
的证明:
我们有。
使用叠加法,我们有。
即有,移项,可得:
。
证毕。
预处理一下
你听,大海与夕阳之间藏着许多金色的旋律
#include <bits/stdc++.h> #define MOD 19940417 #define int long long using namespace std; int n,m; int H(int x){ int res = 0,l = 1,r; while(l <= x){ r = x / (x / l); res += (l + r) * (r - l + 1) / 2 % MOD * (x / l) % MOD,res %= MOD; l = r + 1; } return res; } int H2(){ int res = 0,l = 1,r; while(l <= n){ r = m / (m / l); if(r > n) {res += (l + n) * (n - l + 1) / 2 % MOD * (m / l) % MOD,res %= MOD;} else {res += (l + r) * (r - l + 1) / 2 % MOD * (m / l) % MOD,res %= MOD;} l = r + 1; } return res; } int JD(int l,int r){ int a = r * (r + 1) % MOD * (2 * r + 1) % MOD * 3323403 % MOD; int b = l * (l + 1) % MOD * (2 * l + 1) % MOD * 3323403 % MOD; return (a - b + MOD) % MOD; } int H3(){ int res = 0,l = 1,r; while(l <= n){ r = min(n / (n / l),m / (m / l)); res += JD(l - 1,r) * (n / l) % MOD * (m / l) % MOD,res %= MOD; l = r + 1; } return res; } signed main(){ scanf("%lld%lld",&n,&m);if(n > m) swap(n,m); int a = ((n * n - H(n)) % MOD + MOD) % MOD; int b = ((m * m - H(m)) % MOD + MOD) % MOD; int ans1 = a * b % MOD; int c = n * n % MOD * m % MOD; int d = m % MOD * H(n) % MOD; int e = n % MOD * H2() % MOD; int f = H3(); int ans2 = ((c - d - e + f) % MOD + MOD) % MOD; printf("%lld",(ans1 - ans2 + MOD) % MOD); return 0; }
积性函数
定义
积性函数:积性函数是指对于所有互质的整数
完全积性函数:对于任意整数
性质
若
常见积性函数
狄利克雷卷积
定义
定义两个数论函数
性质
证明:设两个积性函数
和 ,再记 。
设,则: 。
所以:。
证毕。
莫比乌斯函数
定义
性质
性质一
莫比乌斯函数是积性函数。
性质二
证明:
设
由此可得只有在
线性筛求莫比乌斯函数
根据
我可不会变成海上的泡沫,我是可以再来一次的人鱼朵朵!
void getMu(){ vis[1] = 1,mu[1] = 1; for(int i = 2;i <= n;i ++){ if(!vis[i]) Prime[++cnt] = i,mu[i] = -1; for(int j = 1;j <= cnt and i * Prime[j] <= n;j ++){ vis[i * Prime[j]] = 1; if(i % Prime[j] == 0){ mu[i * Prime[j]] = 0; break; } mu[i * Prime[j]] = -mu[i]; } } }
莫比乌斯变换
设
根据
形式一
如果有
这种形式下,数论函数
证明:
方法一:运用卷积
原问题为:已知,求证 。
易知,因此 。( )
方法二:对原式做数论变换
。
第一步是将已知条件带入得到。第二步是变换求和顺序得到(相当于前者先循环在循环 ,后者是先循环 在循环 )。第三部,由性质二可得,只有 的时候后者才为 ,其它情况为 ,故只有在 的时候才能取到值,即 。
证毕。
形式二
如果有
证明
。
拓展
证明
将
因为
该式子两侧同时卷
反演
莫比乌斯反演结论
证明:运用莫比乌斯函数性质二,其正确性显然。证毕。
同时我们也可以得到
欧拉反演结论
证明详见 我的博客——欧拉函数与欧拉定理。
常见的几种反演形式
以下默认
形式一
首先
习题
相当于求
外祖母说,最完美的天籁,用热忱和爱才能唱出来!
#include <bits/stdc++.h> #define N 50004 using namespace std; int vis[N],mu[N],Prime[N],cnt; void getMu(){ vis[1] = 1,mu[1] = 1; for(int i = 2;i <= 50000;i ++){ if(!vis[i]) Prime[++cnt] = i,mu[i] = -1; for(int j = 1;j <= cnt and Prime[j] * i <= 50000;j ++){ vis[i * Prime[j]] = 1; if(i % Prime[j] == 0){ mu[i * Prime[j]] = 0; break; } mu[i * Prime[j]] = -mu[i]; } } for(int i = 2;i <= 50000;i ++) mu[i] += mu[i - 1]; } int JD(int n,int m){ if(n > m) swap(n,m); int res = 0,l = 1,r; while(l <= n){ r = min(n / (n / l),m / (m / l)); res += (mu[r] - mu[l - 1]) * (n / l) * (m / l); l = r + 1; } return res; } int main(){ getMu();int T;scanf("%d",&T);while(T --){ int a,b,c,d,k;scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); printf("%d\n",JD(b / k,d / k) - JD(b / k,(c - 1) / k) - JD((a - 1) / k,d / k) + JD((a - 1) / k,(c - 1) / k)); } return 0; }
形式二
最后一步通过换元令
习题
带着歌声,我们一起去往星辰大海吧!
#include <bits/stdc++.h> #define N 10000000 #define int long long using namespace std; int T,n,m,vis[N + 5],mu[N + 5],Prime[N + 5],cnt,f[N + 5]; void getMu(){ vis[1] = 1,mu[1] = 1; for(int i = 2;i <= N;i ++){ if(!vis[i]) Prime[++cnt] = i,mu[i] = -1; for(int j = 1;j <= cnt and i * Prime[j] <= N;j ++){ vis[i * Prime[j]] = 1; if(i % Prime[j] == 0){ mu[i * Prime[j]] = 0; break; } mu[i * Prime[j]] = -mu[i]; } } for(int i = 1;i <= cnt;i ++){ for(int j = 1;j * Prime[i] <= N;j ++){ f[j * Prime[i]] += mu[j]; } } for(int i = 1;i <= N;i ++) f[i] += f[i - 1]; } int H(int x){ int res = 0,l = 1,r; while(l <= x){ r = min(n / (n / l),m / (m / l)); res += (f[r] - f[l - 1]) * (n / l) * (m / l); l = r + 1; } return res; } signed main(){ getMu(); scanf("%lld",&T);while(T --){ scanf("%lld%lld",&n,&m); if(n > m) swap(n,m); printf("%lld\n",H(n)); } return 0; }
形式三
习题
类似形式一习题一容斥,把它分成四部分。
你小时候都一个人长大,没有伙伴儿么,我都有两条小鱼呢。
#include <bits/stdc++.h> #define N 50004 #define int long long #define MOD 1000000007 using namespace std; int vis[N],phi[N],Prime[N],cnt; void getPhi(){ vis[1] = 1,phi[1] = 1; for(int i = 2;i <= 50000;i ++){ if(!vis[i]) Prime[++cnt] = i,phi[i] = i - 1; for(int j = 1;j <= cnt and i * Prime[j] <= 50000;j ++){ vis[i * Prime[j]] = 1; if(i % Prime[j] == 0){ phi[i * Prime[j]] = phi[i] * Prime[j]; break; } phi[i * Prime[j]] = phi[i] * (Prime[j] - 1); } } for(int i = 1;i <= 50000;i ++) phi[i] = (phi[i] + phi[i - 1]) % MOD; } int JD(int n,int m){ if(n > m) swap(n,m); int res = 0,l = 1,r; while(l <= n){ r = min(n / (n / l),m / (m / l)); res += (phi[r] - phi[l - 1] + MOD) % MOD * (n / l) * (m / l) % MOD,res %= MOD; l = r + 1; } return res; } signed main(){ int T,n,m;scanf("%lld%lld%lld",&T,&n,&m);getPhi();while(T --){ int a,b,c,d;scanf("%lld%lld%lld%lld",&a,&b,&c,&d);a -= 1,b -= 1; printf("%lld\n",((JD(c,d) - JD(a,d) - JD(c,b) + JD(a,b)) % MOD + MOD) % MOD); } return 0; }
形式四
首先我们先了解一个结论:
证明
由于函数是积性函数,所以我们不妨将每一个质因子分开考虑:
设分别含有 个质因子 ,显然等式左侧可以选择的因子的个数为 个。对于右侧而言,显然也有 中,即要么 , 的选择方法为 个;要么 , 的选择方法为 个,要么二者都为 。因此等式两边相等。
证毕。
6。啥时候想回来补就回来补。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】