莫比乌斯反演(数论学习)
积性函数
定义
单位函数:\(\varepsilon(n)=[n=1]\),当且仅当n为1时为1,其余情况为0
恒等函数:\(id_k(n)=n^k,id_1(n)记作id(n)\)
常数函数:\(1(n)=1\),n为任意数函数值都为1
除数函数:\(\sigma_k(n)=\sum_{d|n}d^k\),\(\sigma_0(n)记作d(n),表示n的因数个数;\sigma_1(n)记作\sigma(n),可看作\sigma_0(0)*d\)
欧拉函数:\(\varphi(n)=\sum_{i=1}^n[gcd(i,n)=1]\),表示从1到n和n互质的数的个数
莫比乌斯函数
公式
\(\varepsilon=\mu * 1 \iff \varepsilon(n)=\sum_{d\mid n}\mu(d)\)
\(d=1 * 1 \iff d(n)=\sum_{d\mid n}1\)
\(\sigma=\operatorname{id} * 1 \iff\sigma(n)=\sum_{d\mid n}d\)
\(\varphi=\mu * \operatorname{id} \iff \varphi(n)=\sum_{d\mid n}d\cdot\mu(\frac{n}{d})\)
莫比乌斯函数
定义
\(\mu(n)= \begin{cases} 1&n=1\\0&n\text{ 含有平方因子}\\ (-1)^k&k\text{ 为 }n\text{ 的不同单个质因子的个数}\\\end{cases}\)
性质
- \(d|n表示d是n的因子\)
\(\sum_{d\mid n}\mu(d)= \begin{cases} 1&n=1\\ 0&n\neq 1\\ \end{cases}\)
\(=>\sum_{d\mid n}\mu(d)=[n=1]=\varepsilon(n)\)
\(=>\mu * 1 =\varepsilon\)
- 反演结论
\(\displaystyle [\gcd(i,j)=1]=\sum_{d\mid\gcd(i,j)}\mu(d)\)
实现
线性筛实现
void getMu() {
mu[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!flag[i]) prime[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && i * prime[j] <= n; ++j) {
flag[i * prime[j]] = 1;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
}
mu[i * prime[j]] = -mu[i];
}
}
}
莫比乌斯反演
公式
\(设数论函数f(n),g(n)\)
\(f(n)=\sum_{d\mid n}g(d)=>g(n)=\sum_{d\mid n}\mu(d)f(\frac{n}{d})\)
\(f(n)=\sum_{n|d}g(d)=>g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)
\([gcd(i,j)=1]=\sum_{d|gcd(i,j)}\mu(d)\)
\(\sum_{d|n}\mu(d)=[n=1]\)
莫比乌斯函数和欧拉函数的关系
\(\frac{\phi(n)}{n}=\sum_{d|n}\frac{\mu(d)}{d}\)
例题
P2522 [HAOI2011]Problem b
P2522 [HAOI2011]Problem b
题意
\(对于给出的 n 个询问,每次求有多少个数对 (x,y),满足 a \le x \le b,c \le y \le d,且 \gcd(x,y) = k,\gcd(x,y) 函数为 x 和 y 的最大公约数。\)
题解
由题意可得求得公式为\(\sum_{i=a}^b\sum_{j=c}^d[\gcd(i,j)=k]\)
\(=>\sum_{i=1}^b\sum_{j=1}^d[\gcd(i,j)=k]-\sum_{i=1}^a\sum_{j=1}^d[\gcd(i,j)=k]-\sum_{i=1}^b\sum_{j=1}^c[\gcd(i,j)=k]+\sum_{i=1}^a\sum_{j=1}^b[\gcd(i,j)=k]\)
对于上述的任意部分可以进行推导
\(\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k]\)
\(=>\sum_{i=1}^{\lfloor \frac{n}{k} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{k} \rfloor}[\gcd(i,j)=1]\)
\(=>\sum_{i=1}^{\lfloor \frac{n}{k} \rfloor}\sum_{j=1}^{\lfloor \frac{m}{k} \rfloor}\sum_{d|gcd(i,j)}\mu(d)\)
\(=>\sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k}\rfloor)}\mu(d)\sum_{i=1}^{\lfloor \frac{n}{k} \rfloor}\lfloor d|i \rfloor \sum_{j=1}^{\lfloor \frac{m}{k} \rfloor}\lfloor d|j \rfloor\)
\(=>\sum_{d=1}^{min(\lfloor \frac{n}{k} \rfloor,\lfloor \frac{m}{k}\rfloor)}\mu(d)\lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor\)
然后就能用数论分块求狮子 ^ _ ^ le
数论分块的基本公式就是
\(r=\lfloor \frac{n}{ \lfloor \frac{n}{l} \rfloor} \rfloor\)也就是r=n/(n/l)
然后用(r-l+1)*(n/l)求和
AC代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
const int mod=7;
const int maxn=5e4+10;
int n,k,t;
unordered_map<int,int>mp;
int a[maxn];
int mu[maxn],prime[maxn],vis[maxn],s=0,sum[maxn];
void mub(){//莫比乌斯函数
//*表示和素数筛的区别之处
mu[1]=1;//*
for(int i=2;i<=maxn-10;i++){
if(!vis[i]){
prime[++s]=i;
mu[i]=-1;//*
}
for(int j=1;j<=s&&prime[j]*i<=maxn-10;j++){
vis[prime[j]*i]=1;
if(i%prime[j]==0) {
mu[i*prime[j]] = 0;//*
break;
}
mu[i*prime[j]]=-mu[i];//*
}
}
//预处理求和
for(int i=1;i<=maxn-10;i++){
sum[i]=sum[i-1]+mu[i];
}
}
int slove(int n,int m){
int res=0;
for(int i=1,j;i<=min(n,m);i=j+1){
j=min(n/(n/i),m/(m/i));
res+=(sum[j]-sum[i-1])*(n/i)*(m/i);
}
return res;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
mub();
while(t--){
int a,b,c,d,k;
cin>>a>>b>>c>>d>>k;
cout<<slove(b/k,d/k)-slove(b/k,(c-1)/k)-slove((a-1)/k,d/k)+slove((a-1)/k,(c-1)/k)<<endl;
//容差定理
}
return 0;
}
LCMSUM - LCM Sum
LCMSUM - LCM Sum
题意
给一个数n,求\(lcm(1,n)+lcm(2,n)+......+lcm(n,n)\)的和
题解
由题意可得求得公式为\(\sum_{i=1}^nlcm(i,n)\)
\(=>\sum_{i=1}^n\frac{i*n}{gcd(i,n)}\)
\(=>n*\sum_{i=1}^n\frac{i}{gcd(i,n)}\)
设\(d=gcd(i,n)\)
\(当d|n时,gcd(\frac{i}{d},\frac{n}{d})=1\)
所以每个n的因子d的贡献等于所有数(\(\frac{i}{d}\))的和\(\frac{\phi(d)*d}{2}\)
\(n*\sum_{i=1}^n\frac{i}{gcd(i,n)}=>n*\sum_{d|n}\frac{\phi(d)*d}{2}\)
=_=用文件快读卡过去的
AC代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define ll long long
const int maxn=1e6+10;
int vis[maxn];
ll phi[maxn];
int s=0,prime[maxn];
void init() {
phi[1] = 1;
for(int i = 2; i <= maxn-10; i++) {
if(!vis[i]) prime[++s] = i, phi[i] = i - 1;
for(int j = 1; j <= s && prime[j] * i <= maxn-10; j++) {
vis[prime[j] * i] = 1;
if(i % prime[j] == 0) {
phi[prime[j] * i] = prime[j] * phi[i];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for(int i = 2; i <= maxn-10; i++)
phi[i] = phi[i] * i / 2;
}
void slove() {
int n;
rd(n);
long long res=0;
for(int i=1; i*i<=n; i++) {
if(n%i==0) {
res+=phi[i];
if(i*i<n) {
res+=phi[n/i];
}
}
}
printf("%lld\n",n*res);
}
signed main() {
init();
int t;
rd(t);
while(t--) {
slove();
}
return 0;
}
「BZOJ 2154」Crash 的数字表格
「BZOJ 2154」Crash 的数字表格
题意
一张 n*m 的表格。每个格子里写了一个数字,其中第 i 行第 j 列的那个格子里写着数为 \(\text{lcm}(i, j)\),求这个表格中所有数的和mod20101009是多少
题解
由题意可得求得公式为\(\sum_{i=1}^n\sum_{j=1}^mlcm(m,n)\)
\(=>\sum_{i=1}^n\sum_{j=1}^m\frac{i*j}{gcd(i,j)}\)
\(=>\sum_{i=1}^n\sum_{j=1}^m\sum_{d|i,d|j,gcd(\frac{i}{d},\frac{j}{d})=1}\frac{i*j}{d}\)
以d为基准转化成\(\sum_d^{min(n,m)}d\sum_{i=1}^{\lfloor\frac{i}{d} \rfloor}\sum_{j=1}^{\lfloor\frac{j}{d} \rfloor}[gcd(i,j)=1]i*j\)
可以将上面的公式转化成两个部分,\(\sum_d^{min(n,m)}d\)和\(\sum_{i=1}^{\lfloor\frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor\frac{m}{d} \rfloor}[gcd(i,j)=1]i*j\)
对于后半部分设\(n2=\frac{n}{d},m2=\frac{m}{d}\),原式\(=>\sum_{d=1}^{min(n2,m2)}\sum_{d|i}^{n2}\sum_{d|j}^{m2}\mu(d)*i*j\)
然后提取出一个d使得原来的式子\(=>\sum_{d=1}^{min(n2,m2)}\mu(d)*d^2\sum_{i=1}^{\lfloor\frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor\frac{m}{d} \rfloor}i*j\)
然后分成两个部分\(\sum_{d=1}^{min(n2,m2)}\mu(d)*d^2\)和\(\sum_{i=1}^{\lfloor\frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor\frac{m}{d} \rfloor}i*j\)
对于后半部分可以用公式求,前半部分可以预处理一下,求总和用分块处理
最后返回的结果再进行分块处理就ok了
mod半天发现自己mod错了但还以为是式子退错了就又推了半天的人就是逊啊
AC代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e7+10;
const int mod=20101009;
int mu[maxn],vis[maxn],prime[maxn],s=0;
void init(){
mu[1]=1;
for(int i=2;i<=maxn-10;i++){
if(!vis[i]){
mu[i]=-1;
prime[++s]=i;
}
for(int j=1;j<=s&&prime[j]*i<=maxn-10;j++){
vis[prime[j]*i]=1;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=maxn-10;i++){
mu[i]=(mu[i-1]%mod+(i*i%mod*(mu[i]+mod)%mod)%mod)%mod;
}
}
int g(int n,int m){
return ((((n+1)*n/2%mod)*((m+1)*m/2%mod)%mod)+mod)%mod;
}
int sum(int n,int m){
int res=0;
for(int i=1,j;i<=min(n,m);i=j+1){
j=min(n/(n/i),m/(m/i));
res=(res+((mu[j]-mu[i-1]+mod)%mod)*(g(n/i,m/i)%mod)%mod)%mod;
}
return res;
}
void slove() {
int n,m;
cin>>n>>m;
int res=0;
for(int i=1,j;i<=min(n,m);i=j+1){
j=min(n/(n/i),m/(m/i));
res+=(((i+j)*(j-i+1)/2%mod*sum(n/i,m/i)%mod)%mod+mod)%mod;
res%=mod;
}
cout<<res%mod<<endl;
}
signed main() {
init();
slove();
return 0;
}

浙公网安备 33010602011771号