数论函数/莫比乌斯反演
1.1积性函数
数论函数:可以认为是定义在整数上的函数。
1)积性函数定义
(a,b) = 1,f(a,b) = f(a)f(b)
2)积性函数性质
-
对于积性函数\(f\),是被所有\(p^e\)处的值决定的,即积性函数的值完全由素数的幂次决定
a = 1,f(b) = f(1)f(b)
\(f(60) = f(4)\times f(15) = f(4)\times f(3)\times f(5)\)
\(n = \prod p^{ei}\)
\(f(n) = \prod f(pi^{ei})\)
对于\(f(4)\)的话就没有办法把它表示成更小的素数幂的形式了,因为\(4 = 2\times 2\)显然\(2\)和\(2\)不互质
- (重要!)积性函数\(\times\)积性函数还是积性函数
1.2 、完全积性函数
1)定义
f(a,b) = f(a)f(b) 不要求(a,b) = 1
\(n = \prod p^{ei}\)
\(f(n) = \prod f(pi)^{ei}\)
- \(f(x) = 1\)
- \(f(x) = x\) \(f(x) = \sqrt{x}\) \(f(x) = x^2\)
-
\[y= \begin{cases} 1,\quad x= 1\\ 0, \quad x\neq 1 \end{cases} \tag{1} \]
1.3常见积性函数
①\(id(x) = x\)
②常数函数\(I(x) = 1\)
③单位函数$ e(x)= [x = 1]=\begin{cases} 1,\quad x= 1\\ 0, \quad x\neq 1 \end{cases}$$
④欧拉函数\(\phi(n) = n\prod_{p|n}(1-\dfrac{1}{p})\)
\(\phi(p^e) = (1-\dfrac{1}{p^e})*p^e = p^e-p^{e-1}\)
⑤因子函数\(d(n)\)因子个数
\(d(p^e) = e+1\) \((p^0p^1...p^e)\)
⑥\(\sigma(n)\)因子和
\(\sigma(p^e) = p^0+p^1+...+p^e = \dfrac{p^{e+1}-1}{p-1}\)
⑦\(\mu(n)\)莫比乌斯函数
1.4 莫比乌斯函数
来看一个特殊的函数:常数函数\(1\)的狄拉克雷逆元,我们称其为莫比乌斯函数\(\mu\)
1. 莫比乌斯函数定义
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
1 | -1 | -1 | 0 | -1 | 1 | -1 | 0 | 0 | 1 |
2.莫比乌斯函数性质
\(\sum_{d|n}\mu(d) = \begin{cases} 1,\quad n=1\\\ 0, \quad n\neq 1\end{cases} \tag{1}\)
即 :\(\sum_{d|n}\mu(d) = e(n),\mu*1 = e\)
人话:一个数\(n\)的所有约数的莫比乌斯函数之和为这个数的单位函数\(e(n)\)
该性质是莫比乌斯反演中最重要的技巧之一。
-
结合\(\phi和\mu\)
\(\sum_{d|n}\dfrac{\mu(d)}{d}=\dfrac{\phi(n)}{n}\)
1.5线性筛求积性函数
线性筛:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn =1000010;
bool is_pri[maxn];
int pri[maxn];
int cnt;
void init(int n)
{
memset(is_pri, true, sizeof(is_pri));
is_pri[1] = false;
cnt = 0;
for (int i = 2; i <= n; i++)
{
if (is_pri[i])
pri[++cnt] = i;
for (int j = 1; j <= cnt && i * pri[j] <= n; j++)
{
is_pri[i * pri[j]] = false;
if (i % pri[j] == 0)break;
}
}
}
由于一个正整数(除\(1\)外)可以通过质因数分解得到,对于非\(1\)的正整数都有:
\(n = p_1^{e_1}*p_2^{e_2}*...*p_k^{e_k}\)
根据积性函数定义,对于一个积性函数\(f(n)\)有:
\(f(n) = f(p_1^{e1})\times f(p_2^{e2})\times ...\times f(p_k^{ek}) = \prod f(p_i^{ei})\)
也就是说我们可以根据质因子推导出由该因子组成的合数。
对于一个合数有:
\(f(n) = f(p_1^{e1})\times f(\dfrac{n}{p_1^{e1}})\)
我们可以用线性筛帮助我们在\(O(n)\)求出\(n\)以内的积性函数值
定义:\(p[i]为i\)的最小质因子,\(pr[cnt]\)记录当前筛出的\(cnt\)个质数,\(pe[i]\)是\(p_1^{e_1}\)的值(标准分解里面的第一项)
-
求出\(pe[i]\).
-
若\(i\neq pe[i]\)说明是合数,我们直接递推\(f(i) = f(pe[i])\times f(\dfrac{i}{pe[i]})\)
若\(i = pe[i]\)刚好是素数幂次,一般能从\(p^{e-1}\)推出\(p^e\)
因子个数:\(d(p^e) = d(p^{e-1})+1\)
因子和:\(\sigma(p^e) = \sigma(p^e-1)+p^e\)
欧拉函数:\(\phi(p^e) = \dfrac{i}{p_i}*(p_{i}-1)\)
莫比乌斯函数:$$ \mu(n)= \begin{cases} 1,\quad n= 1\\ (-1)^k, \quad n = p_1p_2...p_k \\ 0 ,n有平方因子\end{cases} \tag{1} $$
void init(int n)//求各个函数的最小素数因子和指数
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,pe[i] = i,pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])//i和i*pr[j]的最小的素因子是一样的
{
//比如pe[5^3*7] = pr[5^2*7]*5
pe[i*pr[j]] = pe[i]*pr[j];
break;
}
else//说明被更小的质因子筛到了
{
pe[i*pr[j]] = pr[j];
}
}
}
}
//写法1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn =1000010;
int p[maxn],pr[maxn/5],pe[maxn];
int cnt;
void init(int n)//求各个函数的最小素数因子和指数
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,pe[i] = i,pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])//i和i*pr[j]的素因子是一样的
{
pe[i*pr[j]] = pe[i]*pr[j];
break;
}
else
{
pe[i*pr[j]] = pr[j];
}
}
}
}
uint f[N],a,b,ans;
void compute(int n,function<void(int)>calcpe){
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pr[i])calcpe(i);
else f[i] = f[pe[i]]*f[i/pe[i]];//积性函数,把这两个乘起来
}
for(uint i = 1;i<=n;i++)
ans ^= (a*i*f[i]+b);
cout<<ans<<endl;
}
int main()
{
cin>>n>>a>>b;
init(n);
//因子个数
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pe[i])
f[i] = f[i/p[i]]+1;//i/p[i]==>p^{e-1}
else f[i] = f[pe[i]]*f[i/pe[i]];//积性函数,把这两个乘起来
}
for(uint i = 1;i<=n;i++)
ans ^= (a*i*f[i]+b);
cout<<ans<<endl;
//因子和
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pe[i])f[i] = f[i/p[i]]+i;
else f[i] = f[pe[i]]*f[i/pe[i]];
}
for(uint i = 1;i<=n;i++)
ans ^= (a*i*f[i]+b);
cout<<ans<<endl;
//欧拉函数
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pe[i])f[i] = i/p[i]*(p[i]-1);
else f[i] = f[pe[i]]*f[i/pe[i]];
}
for(uint i = 1;i<=n;i++)
ans ^= (a*i*f[i]+b);
cout<<ans<<endl;
//莫比乌斯函数
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pe[i]){
if(i==p[i])f[i] = (uint)(-1);
else f[i] = 0;
}else f[i] = f[pe[i]]*f[i/pe[i]];
}
for(uint i = 1;i<=n;i++)
ans ^= (a*i*f[i]+b);
cout<<ans<<endl;
return 0;
}
//写法2
#include<bits/stdc++.h>
using namespace std;
const int maxn =20010000;
int p[maxn],pr[maxn/5],pe[maxn];
int cnt;
void init(int n)//求各个函数的最小素数因子和指数
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,pe[i] = i,pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])//i和i*pr[j]的素因子是一样的
{
pe[i*pr[j]] = pe[i]*pr[j];
break;
}
else
{
pe[i*pr[j]] = pr[j];
}
}
}
}
//如果单求phi
int phi[maxn];
void phi(int n)
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,phi[i] = i-1,pr[++cnt] = i;
for(int j = 1;j<=cnt&&i*pr[j]<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
phi[i*pr[j]] = phi[i]*pr[j];
break;
}else{
phi[i*pr[j]] = phi[i]*(pr[j]-1);
}
}
}
}
unsigned int f[maxn],a,b,ans,n;
void compute(int n,function<void(int)>calcpe){
ans = 0;
f[1] = 1;
for(int i = 2;i<=n;i++)
{
if(i==pe[i])calcpe(i);
else f[i] = f[pe[i]]*f[i/pe[i]];//积性函数,把这两个乘起来
}
for(int i = 1;i<=n;i++)
ans ^= (a*(unsigned int)i*f[i]+b);
cout<<ans<<endl;
}
int main()
{
cin>>n>>a>>b;
init(n);
//因子个数
compute(n,[&](int x){
f[x] = f[x/p[x]] + 1;
});
//因子和
compute(n,[&](int x){
f[x] = f[x/p[x]] + x;
});
//欧拉函数
compute(n,[&](int x){
f[x] = x/p[x]*(p[x]-1);
});
//莫比乌斯函数
compute(n,[&](int x){
f[x] = x==p[x]?-1:0;
});
return 0;
}
2.1迪利克雷卷积
2.1.1定义
迪利克雷卷积是计算求和问题的有用工具。
设\(f\)和\(g\)是算术函数,记\(f\)和\(g\)的迪利克雷卷积为\(f*g\),
定义为:\((f*g)(n) = h(n) = \sum_{d|n}f(d)g(\dfrac{n}{d}) = \sum_{d_1d_2 = n}f(d_1)g(d_2)\)
卷积有什么含义呢?
给一个特别的栗子:定义恒等函数\(I(n) = n\)、常函数\(1(n) = 1\),
它们的卷积是:\((I*1)(n) = \sum_{d|n}I(d)1(\dfrac{n}{d}) = \sum_{d|n}d*1 = \sum_{d|n}d = \sigma(n)\)
所以记:\(I*1 = \sigma\)
✳常见积性函数
下面积性函数,在迪利克雷卷积中常常用到:
\(id(n)\):单位函数,\(id(n) = n\)
\(I_k(n)\):幂函数,\(I_k(n) = n^k\)
\(e(n):\)元函数,$ e(n) = \begin{cases} 1,\quad n=1\\ 0, \quad n> 1\end{cases} \tag{1}$
\(\sigma(n):\)因数和函数,\(\sigma(n)=\sum_{d|n}d\)
\(d(n):\)约数个数,\(d(n)=\sum_{d|n}1\)
✳迪利克雷卷积函数
将上述数论函数两两做卷积,可以得到一些新的数论函数:
常见的例子
-
❗\(e = \mu*1\)
即\([n=1]=\sum_{d|n}\mu(d)\),莫比乌斯函数性质
-
❗\(Id =\phi*1\)
即\(n = \sum_{d|n}\phi(d)\),即一个数所有约数的欧拉函数之和为这个数
-
\(\sigma_k = Id*1\)
根据除数函数定义:\(\sigma(n)= \sum_{d|n}d^k\)
除数函数与幂函数
欧拉函数与恒等函数
2.1.2性质
- 符合交换律和结合律
- (重要)\(f\)和\(g\)是积性函数=>\(f*g\)是积性函数
3.1莫比乌斯反演
引入
1. 莫比乌斯函数:$$ \mu(n)= \begin{cases} 1,\quad n= 1\ (-1)^k, \quad n = p1p2...pk \ 0 ,n有平方因子\end{cases} \tag{1} $$
❗它有一个与欧拉函数\(n = \sum_{d|n}\phi(d)\)类似的定理。
(补充:欧拉函数这个性质的证明:
若\(p\)是素数,显然有\(\phi(p) = p-1\).
那么对于正整数\(kp\),与它不互质的数只有\(1,p,2p,3p,...,kp\),故\(\phi(p)=k(p-1)(1)\)
对于素数幂次,由(1)可知\(\phi(p^k) =\phi(p*p^{k-1})= p^{k-1}(p-1)\)
对于\(\sum_{d|p^k}\phi(d) = \sum_{d = 1}^{k}\phi(p^d)+1\)(显然这里\(d\)只能取\(1,p,p^2,...,p^k\))
\(=(\sum_{d = 1}^{k}p^d-p^{d-1})+1\)
\(=p^k-p^{k-1}+p^{k-1}-p^{k-2}+...-p+p-1+1\)
\(=p^k\)
由唯一分解定理可知\(\sum_{d|n}\phi(d)=n\)
)
如下:
❗莫比乌斯反演Th1
莫比乌斯函数的和函数在整数\(n\)处的取值\(F(n)=\sum_{d|n}\mu(d)\)满足:\(\sum_{d|n}\mu(d) = \begin{cases} 1,\quad n=1\\\ 0, \quad n> 1\end{cases} \tag{1}\)
证明:
(1)对于\(n = 1\)时,\(F(1) = \mu(1) = 1\)显然成立。
(2)对于\(n>1\)时,根据积性函数的定义:\(F(n) = F(p_1^{e_1})F(p_2^{e_2})...F(p_t^{e_t})\)
因为当\(i>=2\)时,\(\mu(p^i) = 0\),有对于某一项\(F(p^k)=\sum_{d|p^k}\mu(d) = \mu(1)+\mu(p)+\mu(p^2)+...+\mu(p^k)=1+(-1)+0+...+0= 0\)
2.莫比乌斯反演
- 大致过程:给定一个求和柿子,对求和柿子进行变量替换、反演(交换求和顺序)等运算,最终化简为一个能在题目给定的时间范围内求解出的柿子。
- 核心技巧:\([n=1] = e(n) = \sum_{d|n}\mu(d)\)
3.1.1形式
\(f(n) = \sum_{n|d}g(d)=>g(n)= \sum \mu(\dfrac{n}{d})f(d)\)
3.1.2莫比乌斯反演公式
❗莫比乌斯反演Th2
莫比乌斯反演公式。
若\(F\)为\(f\)的和函数,对任意正整数\(n\)满足$F(n)=\sum_{d|n}f(d) \(则有:\)f(n)=\sum_{d|n}\mu(d)F(\dfrac{n}{d})$
约数的莫比乌斯反演:
若:\(f(n) = \sum_{d|n}g(d)\)
则:\(g(n) = \sum_{d|n}\mu(d)f(\dfrac{n}{d})\)
倍数的莫比乌斯反演:
若:\(f(n) = \sum_{d|n}g(d)\)
则:\(g(n) = \sum_{d|n}\mu(\dfrac{n}{d})f(d)\)
❗莫比乌斯反演Th3
设\(f\)是算术函数,它的和函数,它的和函数为\(F(n)=\sum_{d|n}f(d)\),如果\(F\)是积性函数则\(f\)也是。
莫比乌斯反演不需要\(f\)是积性函数。莫比乌斯反演可以将一些函数转化,从而降低计算难度。
3.1.3构造
典例:求\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[gcd(i,j)==d]\)
不妨记\(g(x) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==d]\)
任何让我们构造一个\(f(x)\),这里我们需要用到第二组莫比乌斯反演公式。
那么\(f(x)\)是什么嘞?根据公式可知是若干个\(g(x)\)的和。记\(N = min(n,m)\),即\(\gcd\)的上限,我们可以得到\(f(d) = g(d)+d(2d)+g(3d)+...+g(\lfloor\dfrac{N}{d}\rfloor)\)
即:\(f(d) = \sum_{i = 1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)\bmod d==0]\)
写成公式形式就是:\(g(d) = \sum_{d|p}\mu(\dfrac{p}{d})f(p)\)
接下来问题就是如何求\(f(x)\)。\(f(x)\)是满足\(\gcd(i,j)\)是\(d\)的倍数的数对,显然有\(f(x) = \lfloor\dfrac{n}{x}\rfloor\lfloor\dfrac{m}{x}\rfloor\)
\(g(n) = \sum_{d = 1}^{n}\mu(\dfrac{n}{d})*f(d)\)
eg.莫比乌斯反演
题意:
给定一个函数\(f(1),f(2),…,f(n),\)已知\(f(n)=\sum_{d|n}g(d)\),求\(g(1),g(2),…,g(n)\)。
思路:
\(f(n) = \sum_{n|d}g(d)=>g(n)= \sum \mu(\dfrac{n}{d})f(d)\)
\(f = g*\mu\)
#include<bits/stdc++.h>
using namespace std;
const int N = 1E6+10;
unsigned int A,B,C;
int n,cnt,f[N],p[N],mu[N],pr[N],g[N];
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;
}
int main(){
scanf("%d%u%u%u", &n, &A, &B, &C);
for (int i = 1; i <= n; i++)
f[i] = rng61();
p[1] = 1,mu[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,mu[i] = (unsigned int)-1,pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
mu[i*pr[j]] = 0;
break;
}
else
mu[i*pr[j]] = (unsigned int)-mu[i];
}
}
//g = f*mu
//g[n] = sum_{d|n} f[d]*mu[n/d]
//g[n] = sum_{n = d1*d2} f[d1]*mu[d2]
for(int d1 = 1;d1<=n;d1++)
for(int d2 = 1;d1*d2<=n;d2++)
g[d1*d2] += f[d1]*mu[d2];
unsigned int ans = 0;
for(int i = 1;i<=n;i++)ans^=g[i];
cout<<ans<<endl;
}
法二:
\(f(n) = \sum_{d|n}g(d)\)
\(g(i) = f(i)-\sum_{d|i,d\neq i}g(d)\)
eg2互质数对
题意:
\(T\)组询问,每次给两个数\(n,m\),求有多少对\((i,j)\)满足1\(≤i≤n,1≤j≤m\)并且\(i,j\)互质。
思路:
\(\sum_{i=1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==1]=\sum e(\gcd(i,j))\)
\(e(n) = [n==1]\)
\(e = 1*\mu\)
\(1*\mu = e\)
根据迪利克雷卷积\((\mu*1)(n) = e(n) =\sum_{d|n}\mu(d)*1(\dfrac{n}{d})\)
所以\(e(n) = \sum_{d|n}\mu(d)\)
\(\sum_{i=1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==1]\)
$=\sum_{i=1}^{n}\sum_{j = 1}^{m} e(\gcd(i,j)) $
根据\(\mu*1 = e\)
\(= \sum_{i=1}^{n}\sum_{j = 1}^{m}\sum_{d|gcd(i,j)}\mu(d)\)
我们把\(\gcd(i,j)\)转化为\(d|i\)且\(d|j\)
$ = \sum_{i=1}^{n}\sum_{j = 1}^{m}\mu(d)[d|i][d|j]$
$ = \sum_{d = 1}^{n}\mu(d)\sum_{i = 1}^{n}[d|i]\sum_{j = 1}^{m}[d|j]$
\(=\sum_{d = 1}^{n}\mu(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d} \rfloor\)
后面这一块用整数分块
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10100000, M = 10000000;
int p[N],pr[N/5],n,cnt;
int mu[N],smu[N];
int main()
{
p[1] = 1,mu[1] = 1;
for(int i = 2;i<=M;i++)
{
if(!p[i])p[i] = i,mu[i] = -1,pr[++cnt] = i;
for(int j = 1;j<=cnt&&i*pr[j]<=M;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
mu[i*pr[j]] = 0;
break;
}else{
mu[i*pr[j]] = -mu[i];
}
}
}
for(int i = 1;i<=M;i++)
smu[i] = smu[i-1]+mu[i];
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
if(n>m)swap(n,m);
ll ans = 0;
//for(i~n)因为如果for(1~m)的话,n/l就已经是0了
for(int l = 1;l<=n;l++)
{
int r = min(n/(n/l),m/(m/l));//在[l,r]里面n/l和m/l都是不变的
ans += 1ll*(smu[r]-smu[l-1])*(n/l)*(m/l);
l = r;
}
cout<<ans<<endl;
}
return 0;
}
变式
如果题目改成求\(1<=x<=n,1<=y<=m\)且\(\gcd(x,y)=k\)的对数
题解:现在需要求的是\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==k]\)
变形一下可得:\(\sum_{i = 1}^{\lfloor\frac{n}{k}\rfloor}\sum_{i = 1}^{\lfloor\frac{m}{k}\rfloor}[gcd(i,j)==1]\)
eg3.gcd之和
题意:
T组询问,每次给两个数\(n,m\),求\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\gcd(i,j)\)
思路:
用狄利克雷卷积+提取公因数+整除分块化简
\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\gcd(i,j)\)
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}Id(\gcd(i,j))\)
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}(1*\phi)(\gcd(i,j))\)
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{d|\gcd(i,j)}\phi(d)\)
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{d = 1}^{n}\phi(d)[d|i][d|j]\)
\(=\sum_{d = 1}^{n}\phi(d)\sum_{i = 1}^{n}[d|i]\sum_{j =1}^{m}[d|j]\)
\(=\sum_{d = 1}^{n}\phi(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)
所以:\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\gcd(i,j) = \sum_{d = 1}^{n}\phi(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)
更一般地:如果\(\sum_{d=1}^{min(n,m)}f(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)的求法为:
for (int l = 1, r; l <= min(n, m); l = r + 1)
{
r = min(n / (n / l), m / (m / l));
ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
}
本题代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10100000, M = 10000000;
ll p[N],pr[N/5],n,cnt;
ll phi[N],sphi[N];
int main()
{
p[1] = 1,phi[1] = 1;
for(int i = 2;i<=M;i++)
{
if(!p[i])p[i] = i,phi[i] = i-1,pr[++cnt] = i;
for(int j = 1;j<=cnt&&i*pr[j]<=M;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
phi[i*pr[j]] = phi[i]*pr[j];
break;
}else{
phi[i*pr[j]] = phi[i]*(pr[j]-1);
}
}
}
for(int i = 1;i<=M;i++)
sphi[i] = sphi[i-1]+phi[i];
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
if(n>m)swap(n,m);
ll ans = 0;
//for(i~n)因为如果for(1~m)的话,n/l就已经是0了不用算了
for(int l = 1;l<=n;l++)
{
int r = min(n/(n/l),m/(m/l));//在[l,r]里面n/l和m/l都是不变的
ans += 1ll*(sphi[r]-sphi[l-1])*(n/l)*(m/l);
l = r;
}
cout<<ans<<endl;
}
return 0;
}
eg4.互质集合
题意:
\(T\)组询问,每次给一个数\(n\),问{\(1,2,…,n\)}中有多少个非空子集,满足这些数的最大公约数是\(1\)。输出答案对\(10^9+7\)取模的结果。
思路:
\(\sum_{S\leq\lbrace1,2...n\rbrace }e(\gcd(S))\)
\(=\sum_{S\leq\lbrace1,2...n\rbrace}\sum_{d|\gcd(S)}\mu(d)\)
\(d|\gcd(S)\)说明\(S\)中的每个数都是\(d\)的倍数,有\(\lfloor\frac{n}{d}\rfloor\)个,因为不能是空的,所以\(-1\)
\(=\sum_{d = 1}^{n}\mu(d)(2^{\lfloor\frac{n}{d}\rfloor}-1)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int N = 10100000, M = 10000000;
ll p[N],pr[N/5],n,cnt;
ll mu[N],smu[N],pw[N];
int main()
{
std::ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
p[1] = 1,mu[1] = 1;
for(int i = 2;i<=M;i++)
{
if(!p[i])p[i] = i,mu[i] = -1,pr[++cnt] = i;
for(int j = 1;j<=cnt&&i*pr[j]<=M;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
mu[i*pr[j]] = 0;
break;
}else{
mu[i*pr[j]] = -mu[i];
}
}
}
for(int i = 1;i<=M;i++)
smu[i] = smu[i-1]+mu[i];
pw[0] = 1;//预处理2的幂次
for(int i = 1;i<=M;i++)
pw[i] = pw[i-1]*2%mod ;
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
ll ans = 0;
for(int l = 1;l<=n;l++)
{
ll r = n/(n/l);
ans += 1ll*(smu[r]-smu[l-1])*(pw[n/l]-1)%mod;
ans%=mod;
l = r;
}
if(ans<0)ans+=mod;
cout<<ans<<'\n';
}
return 0;
}
eg5.LCMSUM1
题意:
\(T\)组询问,每次给一个\(n\),输出\((\sum_{i = 1}^{n}[i,n])\bmod 2^{60}\)。
思路:
令\(f(n) = \dfrac{1}{n}\)
\(g(n) = \sum_{d|n}f(d)\mu(\dfrac{n}{d})\)
\(f(n) = \sum_{d|n}g(d)\)
\(\sum_{i = 1}^{n}[i,n]\)
\(=\sum_{i = 1}^{n}i*n*f((i,n))\)
\(=\sum_{i = 1}^{n}i*n*\sum_{d|n,d|i}g(d)\)
\(=n\sum_{d|n}g(d)\sum_{i = 1}^{n}i[i|d]\)
因为\(d\)是\(n\)的因子,所以\(n\)可以被\(d\)整除
\(=n\sum_{d|n}g(d)\sum_{i = 1}^{n}i[i|d]\)
$ = n\sum_{d|n}g(d)\dfrac{\dfrac{n}{d}(\dfrac{n}{d}+1)}{2}$
$ = \dfrac{n^2}{2}\sum_{d|n}g(d)(\dfrac{n}{d}+1)$
$ = \dfrac{n^2}{2}(\sum_{d|n}g(d)\dfrac{n}{d}+\sum_{d|n}g(d))$
$ = \dfrac{n^2}{2}(\sum_{d|n}g(d)\dfrac{n}{d}+f(n))$
$ = \dfrac{n^2}{2}(\sum_{d|n}g(d)\dfrac{n}{d}+\dfrac{1}{n})$
$ = \dfrac{n^2}{2}\sum_{d|n}g(d)\dfrac{n}{d}+\dfrac{n}{2}$
\(= \dfrac{n^3}{2}\sum_{d|n}\dfrac{g(d)}{d}+\dfrac{n}{2}\)
\(g(p^e) = \dfrac{1}{p^e}-\dfrac{1}{p^{e-1}}\)
(补充:\(g(p^e) = \dfrac{1}{p^e}-\dfrac{1}{p^{e-1}}\)的证明:\(\because g(p^e) = \sum_{d|p^e}\mu(\dfrac{p^e}{d})*f(d)\)
又因为我们知道,\(\mu(n)\)只在\(n=1和n=p\)时候有效,那么当\(d=p^e\)时\(\mu(\dfrac{p^e}{d})=1\),当\(d=p^{e-1}\)时\(\mu(\dfrac{p^e}{d})=-1\),其他情况都是0,
那么\(g(p^e)=f(p^e)-f(p^{e-1}),因为f(x) = \dfrac{1}{x}\),所以\(g(p^e) = \dfrac{1}{p^e}-\dfrac{1}{p^{e-1}}\))
\(\dfrac{g^{p^e}}{p^e} = \dfrac{1}{p^{2e}}-\dfrac{1}{p^{2e-1}}\)
\(\sum_{d|n}\dfrac{g^{p^e}}{p^e} = 1- \dfrac{1}{p^1}+ \dfrac{1}{p^2}- \dfrac{1}{p^3}+ \dfrac{1}{p^4}-...- \dfrac{1}{p^{2e-1}}+ \dfrac{1}{p^{2e}}\)
因为是分数,我们给它配一个\((p^e)^2\)进去
令\(h(n) = n^2\sum_{d|n}\dfrac{g(d)}{d}\)
\(h(p^e) = (p^e)^2\sum_{d|n}\dfrac{g^{p^e}}{p^e} = p^{2e}- p^{2e-1}+p^{2e-2}-...+1\)
即:\(h(p^e) = h(p^{e-1})+p^{2e}-p^{2e-1}\)
于是:\(\dfrac{n}{2}+\dfrac{n^3}{2}\sum_{d|n}\dfrac{g(d)}{d}=\dfrac{n}{2}(1+h(n))\)
综上所述:\(\sum_{i = 1}^{n}[i,n] = \sum_{i = 1}^{n}\dfrac{n}{2}(1+h(n))\)
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long u64;
const int N = 10010000,M = 10000000;
int p[N],pr[N/5],n,pe[N],cnt;
u64 h[N];
void init(int n)
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,pe[i] = i,pr[++cnt] = i;
for(int j = 1;j<=cnt&&i*pr[j]<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
pe[i*pr[j]] = pe[i]*pr[j];
break;
}
else
{
pe[i*pr[j]] = pr[j];
}
}
}
}
int main()
{
init(M);
h[1] = 1;
for(int i = 2;i<=M;i++)
{
if(i==pe[i])h[i] = h[i/p[i]]+(u64)i*(i-i/p[i]);
else h[i] = h[pe[i]]*h[i/pe[i]];
}
int T;
cin>>T;
for(int i =1;i<=T;i++)
{
int n;
cin>>n;
u64 ans = n*(1+h[n])/2;
cout<<ans%(1ull<<60)<<endl;
}
return 0;
}
eg6.LCMSUM2
题意:
\(T\)组询问,每次给两个数\(n,m\),求\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[i,j]\bmod 2^{60}。\)
思路:
\([i,j] = \dfrac{i*j}{(i,j)}\)
令\(f(x) = \dfrac{1}{x}\),这里\(f(x)\)还是数论函数,因为对于数论函数我们只要求定义域是整数
\(f(u) = \sum_{d|n}g(d)\)
那么:
\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[i,j]\)
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}\dfrac{i*j}{(i,j)}\)
$ = \sum_{i = 1}^{n}\sum_{j = 1}^{m} ijf((i,j))$
\(=\sum_{i = 1}^{n}\sum_{j = 1}^{m}(i*j)\sum_{d|n} g(d)[d|i][d|j]\)
\(=\sum_{d|n} g(d)\sum_{i = 1}^{n}\sum_{j = 1}^{m}i*j[d|i][d|j]\)
\(=\sum_{d|n} g(d)\sum_{i = 1}^{n}i[d|i]\sum_{j = 1}^{m}j[d|j]\)
\(\sum_{i = 1}^{n}i[d|i] = d\times \dfrac{(1+\lfloor\frac{n}{d}\rfloor)\lfloor\frac{n}{d}\rfloor}{2}\)
于是:
\(\sum_{d|n} g(d)\sum_{i = 1}^{n}i[d|i]\sum_{j = 1}^{m}j[d|j]\)
\(=\sum_{d|n} g(d)\times d^2 \dfrac{(1+\lfloor\frac{n}{d}\rfloor)\lfloor\frac{n}{d}\rfloor(1+\lfloor\frac{m}{d}\rfloor)\lfloor\frac{m}{d}\rfloor}{4}\)
\(f(n) = \sum_{d|n}g(d)\)
\(g(n) = \sum_{d|n}\mu(\dfrac{n}{d})*f(d)\)
\(h(n) = g(n)*n^2\)
\(g(n)\)是积性的,\(n^2\)是积性的,那么乘起来也是积性的,对于积性函数我们只用考虑素数幂次是多少
\(g(p^e) = \dfrac{1}{p^e}-\dfrac{1}{p^{e-1}}\)
\(h(p^e) = p^e-p^{e+1} = p^e*(1-p)\)
\(h(n) = n\sum_{p|n}(1-p)\)
写法一,先求素数幂次:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long u64;
const int N =10000010,M = 10000000;
int p[N],pr[N/5],pe[N];
int cnt;
int f[N],a,b,ans;
u64 h[N];
void init(int n)//求各个函数的最小素数因子和指数
{
p[1] = 1;
for(int i = 2;i<=n;i++)
{
if(!p[i])p[i] = i,pe[i] = i,pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=n;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])//i和i*pr[j]的素因子是一样的
{
pe[i*pr[j]] = pe[i]*pr[j];
break;
}
else
{
pe[i*pr[j]] = pr[j];
}
}
}
}
int main()
{
init(M);
h[1] = 1;
for(int i = 2;i<=M;i++)
{
if(i==pe[i])h[i] = i-(u64)i*p[i];//h(p^e) = p^e(1-p)
else h[i] = h[pe[i]]*h[i/pe[i]];//合数,递推
}
for(int i = 1;i<=M;i++)h[i] += h[i-1];
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
if(n>m)swap(n,m);
u64 ans = 0;
for(int l = 1;l<=n;l++)
{
int d1 = n/l,d2 = m/l;
int r = min(n/d1,m/d2);
ans += (h[r]-h[l-1])*d1*(d1+1)*d2*(d2+1)/4;
l = r;
}
cout<<ans%(1ull<<60)<<endl;
}
return 0;
}
写法二:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long u64;
const int N =10000010,M = 10000000;
int p[N],pr[N/5];
int cnt;
int f[N],a,b,ans;
u64 h[N];
int main()
{
h[1] = 1;
p[1] = 1;
for(int i = 2;i<=M;i++)
{
if(!p[i])p[i] = i,h[i] = i*(u64)(1-i),pr[++cnt] = i;
for(int j = 1;j<=cnt&&pr[j]*i<=M;j++)
{
p[i*pr[j]] = pr[j];
if(p[i]==pr[j])
{
h[i*pr[j]] = h[i]*pr[j];
break;
}
else
{
h[i*pr[j]] = h[i]*pr[j]*(1-pr[j]);
}
}
}
for(int i = 1;i<=M;i++)h[i] += h[i-1];
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
if(n>m)swap(n,m);
u64 ans = 0;
for(int l = 1;l<=n;l++)
{
int d1 = n/l,d2 = m/l;
int r = min(n/d1,m/d2);
ans += (h[r]-h[l-1])*d1*(d1+1)*d2*(d2+1)/4;
l = r;
}
cout<<ans%(1ull<<60)<<endl;
}
return 0;
}
✳总结做题技巧
- \(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==1]\)
根据我们的基本结论:有\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[\gcd(i,j)==1] = \sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{d|gcd(i,j)}\mu(d)\)
我们发现\(i,j\)不是固定的,所有\(\gcd(i,j)\)也是变化的,我们难以直接枚举\(\gcd(i,j)\)的因子。
我们发现\(d|\gcd(i,j)\)等价于\(d|i且d|j\)
所以有:\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}\sum_{d|gcd(i,j)}\mu(d)= \sum_{d = 1}^{min(n,m)}\mu(d)\sum_{i=1}^{n}[d|i]\sum_{j = 1}^{m}[d|j]=\sum_{d=1}^{min(n,m)}\mu(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)
最终问题转化为求解:\(\sum_{d=1}^{min(n,m)}\mu(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)
这个式子我们可以通过整除分块在\(O\sqrt{min(n,m)}\)时间复杂度内解决
核心:\([d|gcd(i,j)]<==>[d|i,d|j]\)
-
整除与循环枚举,循环枚举1,2,⋯,n,循环内的式子每固定长度才会取到,其余均为0,则可以直接缩循环区间。
比如:求解\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}[gcd(i,j)=k]\)
我们换个角度考虑:显然\(i,j\)至少含有\(k\)这个因子,才可能产生贡献。也就是每\([t\times(k-1)+1,t\times k]\)会包含一个\(k\)的倍数
每段至多\(1\)个\(k\)的倍数,我们将\([1,k].[k+1,2k]...[xk+1,n]\)每段缩短为长度为\(1\),那么原本长度为\([1,n]\)就被缩短为\([1,\lfloor\dfrac{n}{d}\rfloor]\),当然最后一个区间可能到达不了完整\(k\)的倍数。
缩完区间之后,选择\(i\)相当于从原本的区间\(i\)中选择了\(i\times k\),那么在缩完区间之后,任从\([1,⌊\dfrac{n}{k}⌋]\)和\([1,⌊\dfrac{m}{k}⌋]\)中选出一个数,映射回去原本的区间就都包含\(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]\)
核心点:内外两层循环,每隔长度\(k\)才会出现一个有用的点,以此来缩短循环区间。
-
将只含有\(\gcd(i,j)\)的式子,转化为含有\([\gcd(i,j)==1]\)的式子
比如:求解\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}f(\gcd(i,j))\),其中\(n<m\)
如何将这类不含有\([\gcd(i,j)==1]\)的形式的柿子转化为\([\gcd(i,j)==1]\)有关呢?
方法:在外层循环多枚举一层最大公约数\(d\),内层循环利用技巧\(1\)缩范围,枚举变量\(i->i',j->j'\)。
\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}f(gcd(i,j))\)
\(=\sum_{d = 1}^{min(n,m)}\sum_{i' = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j' = 1}^{\lfloor\frac{m}{d}\rfloor}f(\gcd(i,j))[\gcd(i',j')==1]\)
\(=\sum_{d = 1}^{n}\sum_{i= 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}f(d)[\gcd(i,j)==1]\)
-
外循环变量为\(d\),内循环变量为\(d'\),式子中出现二者乘积\(T=dd'(1<=T<=n)\)。变形为外循环变量\(t\),内循环枚举约数为\(d\)。
在3中我们得到\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}f(gcd(i,j))\)变形结果为 \(\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}f(d)[\gcd(i,j)==1]\)
接下来对\([\gcd(i,j)==1]\)进行反演
\(\sum_{d = 1}^{n}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}f(d)[\gcd(i,j)==1]\)
\(=\sum_{d = 1}^{n}f(d)\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)==1]\)
\(=\sum_{d = 1}^{n}f(d)\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}\sum_{d'|\gcd(i,j)}\mu(d')\)
\(=\sum_{d = 1}^{n}f(d)\sum_{d' = 1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\sum_{i = 1}^{\lfloor\frac{n}{d}\rfloor}[d'|i]\sum_{j = 1}^{\lfloor\frac{m}{d}\rfloor}[d'|j]\times \mu(d')\)
\(=\sum_{d = 1}^{n}f(d)\sum_{d' = 1}^{min(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)}\lfloor\frac{n}{dd'}\rfloor\lfloor\frac{m}{dd'}\rfloor\times \mu(d')\)
\(=\sum_{d = 1}^{n}f(d)\sum_{d' = 1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{dd'}\rfloor\lfloor\frac{m}{dd'}\rfloor\times \mu(d')\)
-
在上式中,外层循环的变量为\(D\),内层循环的变量为\(d'\),二者的乘积为\(dd'(1<=dd'<=n)\),设\(T=dd'\)
-
在莫反的题目中,式子中出现内外两层循环的变量,如\(T=dd'\),且\(T\)仍然处于\([1,n]\),我们此时将原式变形,外层循环枚举变量\(T\),内层循环枚举其约数\(d\),就容易构造出狄利克雷卷积的形式
\(\sum_{d = 1}^{n}f(d)\sum_{d' = 1}^{\lfloor\frac{n}{d}\rfloor}\lfloor\frac{n}{dd'}\rfloor\lfloor\frac{m}{dd'}\rfloor\times \mu(d')\)
\(=\sum_{T = 1}^{n}\sum_{d|T}f(d)\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\times \mu(\dfrac{T}{d})\)
\(=\sum_{T = 1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}f(d)\times \mu(\dfrac{T}{d})\)
于是我们就构造出了内循环为狄利克雷卷积
设\(g = \sum_{d|T}f(d)\times \mu(\dfrac{T}{d})\)
即\(g = f*\mu\)
所以原柿等于:\(=\sum_{T = 1}^{n}g(T)\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\)
-
-
对于所有带\(\gcd\)的,我们有一般求解通式
\(\sum_{i = 1}^{n}\sum_{j = 1}^{m}f((i,j))\)
对于以上我们都能找到数论函数\(g\)满足\(f(n) = \sum_{d|n}g(d)\),即\(g = f*\mu\)
\(f((i,j)) = \sum_{d|(i,j)}g(d)\)
我们把\(d\)提出来
$\sum_{d = 1}^{n}g(d)\sum_{i = 1}^{n}\sum_{j = 1}^{m}[d|i][d|j] $
\(= \sum_{d=1}^{n}g(d)\lfloor\dfrac{n}{d}\rfloor\lfloor\dfrac{m}{d}\rfloor\)
其中\(g(d) = \sum_{d|n}f(d)\mu(\dfrac{n}{d})\)
显然:\(g = f*\mu\)
以上方法对所有带\(\gcd\)的均适用
但这个通式的限制性过强,内层式子必须只和\(gcd(i,j)\)有关,即只能是一个一元函数,故使用范围有限
-
将\(\sum_{i = 1}^{n}\sum_{j= i}^{n}f(i,j)\)和\(\sum_{i = 1}^{n}\sum_{j= 1}^{n}f(i,j)\)转化
\(\sum_{i = 1}^{n}\sum_{j= 1}^{n}f(i,j)\)
$ = \dfrac{\sum_{i = 1}^{n}(f(i,i)+\sum_{j= 1}^{n}f(i,j)}{2}$
\(= \dfrac{\sum_{i = 1}^{n}\sum_{j = 1}^{n}f(i,j)+\sum_{i= 1}^{n}f(i,i)}{2}\)
将\(\sum_{i = 1}^{n}\sum_{j= i}^{n}f(i,j)\)和\(\sum_{i = 1}^{n}\sum_{j= 1}^{n}f(i,j)\)转化:
\(\sum_{i = 1}^{n}\sum_{j= 1}^{n}f(i,j)\)
\(=\sum_{i \neq j}f(i,j)+\sum_{i = j}f(i,j)\)
\(=2\sum_{i = 1}^{n}\sum_{j = i+1}^{n}f(i,j)+\sum_{i = j}^{n}f(i,i)\)
\(=2\sum_{i = 1}^{n}\sum_{j = i}^{n}f(i,j)-\sum_{i = 1}^{n}f(i,i)\)
在竞赛中,莫比乌斯反演常常涉及到数论题中两个常用的小技巧:提取公因数,整除分块。