写在前面
该来的总会来,终究逃不过圈套。。
爱数学!但是对这种个人认为极其复杂的数学有种莫名的恐惧。。
前置芝士
反演
什么是反演?
参照学长 LB 的 「笔记」反演 。
积性函数
定义域为正整数的算术函数 (f(x)) 满足
一些常见的积性函数
-
欧拉函数 (varphi(n) = sum limits_{i=1}^n [gcd(i,n)=1])
-
莫比乌斯函数 (mu(n))
-
最大公约数 (gcd(n,k))
完全积性函数
定义域为正整数的算术函数 (f(x)) 满足
常见完全积性函数
-
恒等函数 (I(n)=1)
-
元函数 (epsilon(n)=[n=1])
-
单位函数 (id(n)=n)
狄利克雷卷积(Dirichiet)
对于两算术函数 (f,g) ,定义 ((f * g)(n )=sum_{d mid n} f(d) gleft(frac{n}{d} ight)) ,其中 (n) 常常省略不写。
运算律
交换律
结合律
分配律
应用
理论 1
其中
则有
理论 2
其中 (id(n)=n) ,
则有
即 任何数的 (varphi) 之和都是它本身 。
理论 3
证明:
有
其中
所以 (mu * id = varphi)
注意:(epsilon) 可看作数论函数中的 (1) 。
莫比乌斯函数
这里详细说明一下上文提到的 (mu) ,即莫比乌斯函数 。
定义
莫比乌斯函数定义为
性质
莫比乌斯函数是积性函数,具有一下性质
证明:
设 (n=prod limits_{i=1}^{k} p_{i}^{c_{i}}, n^{prime}=prod limits_{i=1}^{k} p_{i})
由莫比乌斯函数定义有
若 (n^prime) 的某因子 (d) ,有 (mu(d)=(-1)^prime) ,则它由 (i) 个本质不同的质因子组成。
由于质因子总数为 (k),满足上式的因子数为 (C_k^i) 。
对于原式,可转化为枚举 (mu(d)) 的值
根据二项式定理,上式可化为
显然当 (k=0) ,即 (n=0) 时为 (1) ,否则为 (0) 。
线性筛求莫比乌斯函数
(mu) 为积性函数,因此可以线性筛求莫比乌斯函数。
/*
线性筛求莫比乌斯函数
By Luckyblock
有删改。
*/
int pnum, mu[_], p[_];
bool vis[_];
void Euler(int lim_)
{
vis[1] = true;
mu[1] = 1ll;
for (int i = 2; i <= lim_; ++i)
{
if (!vis[i])
{
p[++pnum] = i;
mu[i] = -1;
}
for (int j = 1; j <= pnum && i * p[j] <= lim_; ++j)
{
vis[i * p[j]] = true;
if (!(i % p[j]))
{ //勿忘平方因子
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = -mu[i];
}
}
}
莫比乌斯反演
定义
设 (f(n),g(n)) 两个数论函数,
若
则有
证明
利用狄利克雷卷积卷积,原问题可化为
已知 (f = g * I) ,证明 (g= f * mu) 。
显然有
证毕。
应用
这里有一个套路,一般涉及到莫比乌斯反演的题目都可以按照这个思路来。
zhx 亲授/kel
求 (sum limits_{i=1}^n sum limits_{j=1}^m gcd(i,j)) 的值。
“反正这题数据范围暴力肯定过不了,其他无所谓。——zhx
显然,直接暴力枚举 (O(nmlog))肯定过不了。。
能否在 (O(n)) 的时间内求解呢?
这里可以用一个非常奇妙的思想——求和变形。
-
增加枚举变量
由 (id = varphi * I) 有
[egin{align} & sum limits_{i=1}^n sum limits_{j=1}^m gcd(i,j) \ =& sum limits_{i=1}^n sum limits_{j=1}^m id[ gcd(i,j)] \ =& sum limits_{i=1}^n sum limits_{j=1}^m sum limits_{d mid gcd(i,j)} varphi(d) * I \ =& sum limits_{i=1}^n sum limits_{j=1}^m sum limits_{d mid gcd(i,j)} varphi(d) end{align} ] -
交换枚举顺序
[egin{align} &sum limits_{i=1}^n sum limits_{j=1}^m sum limits_{d mid gcd(i,j)} varphi(d) ag{4}\ &=sum limits_{d=1}^n sum limits_{i=1}^{leftlfloorfrac{n}{d} ight floor} sum limits_{j=1}^{leftlfloorfrac{m}{d} ight floor} varphi(d) ag{5} end{align} ] -
删除无用变量
[egin{align} & sum limits_{d=1}^n sum limits_{i=1}^{leftlfloorfrac{n}{d} ight floor} sum limits_{j=1}^{leftlfloorfrac{m}{d} ight floor} varphi(d) ag{5} \ =& sum limits_{d=1}^n leftlfloorcfrac{n}{d} ight floor leftlfloorcfrac{m}{d} ight floor varphi(d) ag{6} end{align} ]
然后就可以直接枚举 (d=1 sim n) 求解答案。
时间复杂度 (O(n)) 。
/*
Name: P2398 GCD SUM
Solution:
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int n;
const int _ = 1000010;
int prime[_], v[_], phi[_], cnt;
int res[_];
int ans;
/*=============================================自定义函数*/
void eular(int n) //线性筛筛欧拉函数
{
memset(v, 0, sizeof(v));
phi[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!v[i])
{
prime[++cnt] = v[i] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= cnt; j++)
{
if (prime[j] > v[i] || i * prime[j] > n)
break;
v[i * prime[j]] = prime[j];
phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
}
// sumPhi[i] = sumPhi[i - 1] + phi[i];
}
}
/*=================================================主函数*/
signed main()
{
n = read();
eular(n);
for (int i = 1; i <= n; i++)
ans += (n / i) * (n / i) * phi[i];
printf("%lld
", ans);
return 0;
}
最后
鸣谢 :
如果存在错误,感谢指出。