1.前置知识
(1) 数论分块
之前写过专门说这个的了,传送门
大致是求形如
∑
i
=
1
n
⌊
n
i
⌋
\sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor
i=1∑n⌊in⌋
代码也很短,主要是:
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
(2)莫比乌斯函数
这是来自百度百科的解释:
简单来说就是
- 当 n = 1 n=1 n=1时, μ ( n ) = 1 \mu(n)=1 μ(n)=1
- n n n分解质因数后,没有幂次大于平方的质因子, μ ( n ) = ( − 1 ) k \mu(n)=(-1)^k μ(n)=(−1)k
- 只要当 n n n含有任何质因子的幂次大于等于2, μ ( n ) = 0 \mu(n)=0 μ(n)=0.
(3)狄利克雷卷积之常用性质1(非常重要/常用)
μ ∗ 1 = ϵ \mu * 1=\epsilon μ∗1=ϵ
对于任意正整数n
∑
d
∣
n
μ
(
d
)
=
ϵ
(
n
)
=
[
n
=
1
]
\sum_{d|n} \mu(d) = \epsilon(n) = [n=1]
d∣n∑μ(d)=ϵ(n)=[n=1]
[
n
=
1
]
[n=1]
[n=1]表示只有当
n
=
1
n=1
n=1成立时,返回值为1否则,值为0。
我们在莫比乌斯反演中套路是这样的:
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
[ gcd(i,j)=1 ] = \sum_{d|gcd(i,j)} \mu(d)
[gcd(i,j)=1]=d∣gcd(i,j)∑μ(d)
(2) 狄利克雷卷积之常用性质2
ϕ ∗ 1 = I d \phi * 1 = Id ϕ∗1=Id
其中 I d Id Id函数表示 I d k ( x ) = x k Id_k(x) = x^k Idk(x)=xk
其实还有如下结论:
以及一条还不知道有啥用的公式:
∑
d
∣
n
μ
(
d
)
d
=
ϕ
(
n
)
n
\sum_{d|n} \frac{\mu(d)}{d} = \frac{ \phi(n) }{n}
d∣n∑dμ(d)=nϕ(n)
2.莫比乌斯反演
咱们终于进入正题啦!
定理
设
f
(
n
)
f(n)
f(n)和
g
(
n
)
g(n)
g(n)是定义在非负整数集合上的两个函数,并且满足条件:
f
(
n
)
=
∑
d
∣
n
g
(
d
)
f(n) = \sum_{d|n}g(d)
f(n)=d∣n∑g(d)
那么有:
g
(
n
)
=
∑
d
∣
n
μ
(
d
)
f
(
⌊
n
d
⌋
)
g(n) = \sum_{d|n} \mu(d) f( \lfloor \frac{n}{d} \rfloor )
g(n)=d∣n∑μ(d)f(⌊dn⌋)
证明
方法一 数论推导
∑ d ∣ n μ ( d ) f ( n d ) = ∑ d ∣ n μ ( d ) ∑ k ∣ n d g ( k ) = ∑ k ∣ n g ( k ) ∑ d ∣ n k μ ( d ) = g ( n ) \sum_{d|n} \mu(d)f( \frac{n}{d} ) = \sum_{d|n}\mu(d) \sum_{k|\frac{n}{d}}g(k) = \sum_{k|n}g(k)\sum_{d|\frac{n}{k}}\mu(d) = g(n) d∣n∑μ(d)f(dn)=d∣n∑μ(d)k∣dn∑g(k)=k∣n∑g(k)d∣kn∑μ(d)=g(n)
用
∑
k
∣
n
d
g
(
k
)
\sum_{k|\frac{n}{d}} g(k)
∑k∣dng(k)代替
f
(
n
d
)
f(\frac{n}{d})
f(dn),然后变换求和顺序,最后一步的依据是
∑
d
∣
n
μ
(
d
)
=
[
n
=
1
]
\sum_{d|n} \mu(d) = [n=1]
d∣n∑μ(d)=[n=1]
方法二 狄利克雷卷积推导
当然莫比乌斯反演还有另外一种形式:
如果有
f
(
n
)
=
∑
n
∣
d
g
(
d
)
f(n) = \sum_{n|d}g(d)
f(n)=n∣d∑g(d)
那么有
g
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
f
(
d
)
g(n) = \sum_{n|d}\mu(\frac{d}{n})f(d)
g(n)=n∣d∑μ(nd)f(d)
3.例题
我一看到那个需要设函数的莫比乌斯反演公式就烦躁,所以下面的推导决定不用那个公式。开始看例题前我们先回忆下这个公式:
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
[gcd(i,j)=1] = \sum_{d|gcd(i,j)}\mu(d)
[gcd(i,j)=1]=d∣gcd(i,j)∑μ(d)
(以下例题全部默认
n
<
m
n<m
n<m,且所有分式都是向下取整!!!)
例题1
求
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
1
]
\sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)=1]
i=1∑nj=1∑m[gcd(i,j)=1]
我们直接套公式就好啦:
=
∑
i
=
1
n
∑
j
=
1
m
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
n
μ
(
d
)
∑
i
=
1
n
d
∑
j
=
1
m
d
=
∑
d
=
1
n
μ
(
d
)
∗
⌊
n
d
⌋
∗
⌊
m
d
⌋
=\sum_{i=1}^n \sum_{j=1}^m \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^n \mu(d)\sum_{i=1}^\frac{n}{d} \sum_{j=1}^\frac{m}{d} \\ =\sum_{d=1}^n \mu(d) * \lfloor \frac{n}{d} \rfloor * \lfloor \frac{m}{d} \rfloor
=i=1∑nj=1∑md∣gcd(i,j)∑μ(d)=d=1∑nμ(d)i=1∑dnj=1∑dm=d=1∑nμ(d)∗⌊dn⌋∗⌊dm⌋
我们会注意到后面那块是可以数论分块
O
(
n
)
O(\sqrt[]{n})
O(n)处理的
例题2
求
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)=k]
i=1∑nj=1∑m[gcd(i,j)=k]
解法:
=
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
k
,
j
k
)
=
1
]
=
∑
i
=
1
n
k
∑
j
=
1
m
k
[
g
c
d
(
i
,
j
)
=
1
]
=\sum_{i=1}^n \sum_{j=1}^m[gcd( \frac{i}{k} , \frac{j}{k} )=1] \\ =\sum_{i=1}^{\frac{n}{k}}\sum_{j=1}^{\frac{m}{k}}[gcd(i,j)=1]
=i=1∑nj=1∑m[gcd(ki,kj)=1]=i=1∑knj=1∑km[gcd(i,j)=1]
例题3
求:
∑
i
=
1
n
∑
j
=
1
m
i
j
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=1}^n \sum_{j=1}^mij[gcd(i,j)=k]
i=1∑nj=1∑mij[gcd(i,j)=k]
解:
=
∑
i
=
1
n
∑
j
=
1
m
i
j
[
g
c
d
(
i
k
,
j
k
)
=
1
]
=
∑
i
=
1
n
k
∑
j
=
1
m
k
i
j
[
g
c
d
(
i
,
j
)
=
1
]
k
2
=
∑
i
=
1
n
k
∑
j
=
1
m
k
i
j
k
2
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
n
μ
(
d
)
d
2
∑
i
=
1
n
k
d
∑
j
=
1
m
k
d
i
j
k
2
=\sum_{i=1}^n \sum_{j=1}^m ij [gcd( \frac{i}{k} , \frac{j}{k} )=1] \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} ij[gcd(i,j)=1]k^2 \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} ijk^2 \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^n \mu(d) d^2 \sum_{i=1}^{\frac{n}{kd}} \sum_{j=1}^{\frac{m}{kd}}ijk^2
=i=1∑nj=1∑mij[gcd(ki,kj)=1]=i=1∑knj=1∑kmij[gcd(i,j)=1]k2=i=1∑knj=1∑kmijk2d∣gcd(i,j)∑μ(d)=d=1∑nμ(d)d2i=1∑kdnj=1∑kdmijk2
这里要说一下
为什么会多一个 d 2 d^2 d2和 k 2 k^2 k2 啊?
因为求和上下线限变了之后,gcd变成了可以用套路式换掉的样子,但是中间的 i j ij ij这一项缩小到了原来的 1 k 2 \frac{1}{k^2} k21倍,所以需要乘回去。 d 2 d^2 d2同理。
例题4
求
∑
i
=
1
n
∑
j
=
1
m
l
c
m
(
i
,
j
)
\sum_{i=1}^n \sum_{j=1}^m lcm(i,j)
i=1∑nj=1∑mlcm(i,j)
解:
=
∑
i
=
1
n
∑
j
=
1
m
i
j
g
c
d
(
i
,
j
)
=
∑
d
=
1
n
∑
i
=
1
n
∑
j
=
1
m
i
j
d
[
g
c
d
(
i
,
j
)
=
d
]
=
∑
d
=
1
n
∑
i
=
1
n
d
∑
j
=
1
m
d
i
∗
j
∗
d
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
=
1
n
∑
i
=
1
n
d
∑
j
=
1
m
d
i
∗
j
∗
d
∑
k
∣
g
c
d
(
i
,
j
)
μ
(
k
)
=
∑
d
=
1
n
d
∑
k
=
1
n
d
μ
(
k
)
∑
i
=
1
n
d
k
∑
j
=
1
m
d
k
i
∗
j
∗
k
2
=\sum_{i=1}^n \sum_{j=1}^m \frac{ij}{gcd(i,j)} \\ =\sum_{d=1}^n \sum_{i=1}^n \sum_{j=1}^m\frac{ij}{d}[gcd(i,j)=d] \\ =\sum_{d=1}^n \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{m}{d}}i*j*d[gcd(i,j)=1] \\ =\sum_{d=1}^n \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{m}{d}}i*j*d \sum_{k|gcd(i,j)}\mu(k) \\ =\sum_{d=1}^n d \sum_{k=1}^{\frac{n}{d}}\mu(k) \sum_{i=1}^{\frac{n}{dk}} \sum_{j=1}^{\frac{m}{dk}}i*j*k^2
=i=1∑nj=1∑mgcd(i,j)ij=d=1∑ni=1∑nj=1∑mdij[gcd(i,j)=d]=d=1∑ni=1∑dnj=1∑dmi∗j∗d[gcd(i,j)=1]=d=1∑ni=1∑dnj=1∑dmi∗j∗dk∣gcd(i,j)∑μ(k)=d=1∑ndk=1∑dnμ(k)i=1∑dknj=1∑dkmi∗j∗k2
4.练习题
T1 ZAP-Queries
求
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)=k]
i=1∑nj=1∑m[gcd(i,j)=k]
解:
=
∑
i
=
1
n
k
∑
j
=
1
m
k
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
i
=
1
n
k
∑
j
=
1
m
k
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
d
=
1
n
k
μ
(
d
)
∑
i
=
1
n
k
d
∑
j
=
1
n
k
d
=
∑
d
=
1
n
k
μ
(
d
)
⌊
n
k
d
⌋
⌊
m
k
d
⌋
=\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} [gcd(i,j)=1] \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^{\frac{n}{k}} \mu(d) \sum_{i=1}^{\frac{n}{kd}} \sum_{j=1}^{\frac{n}{kd}} \\ =\sum_{d=1}^{\frac{n}{k}} \mu(d) \lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor
=i=1∑knj=1∑km[gcd(i,j)=1]=i=1∑knj=1∑kmd∣gcd(i,j)∑μ(d)=d=1∑knμ(d)i=1∑kdnj=1∑kdn=d=1∑knμ(d)⌊kdn⌋⌊kdm⌋
先线性筛一下莫比乌斯函数,然后用一下整除分块就好啦
ACcode:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 50100;
bool pd[N];
int n,m,k,mu[N],tot=0,pr[N];
LL sum[N];
void pre(int n)
{
pd[1] = true;
mu[1] = 1;
for(int i=2;i<=n;i++)
{
if( pd[i]==false )
{
tot++;
pr[tot] = i;
mu[i] = -1;
}
for(int j=1;j<=tot&&i*pr[j]<=n;j++)
{
pd[ i*pr[j] ] = true;
if( i%pr[j]==0 )
{
// mu[ i&pr[j] ] = 0;
break;
}
else mu[ i*pr[j] ] = -mu[i];
}
}
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + mu[i];
}
LL ans = 0;
void solve()
{
scanf("%d %d %d",&n,&m,&k);
if( n>m ) swap(n,m);
ans = 0;
n /= k;
m /= k;
for(int l=1,r;l<=n;l=r+1)
{
r = min( n/(n/l) , m/(m/l) );
ans += 1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
}
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
pre(50000);
int t;
cin>>t;
while( t-- )
{
solve();
}
return 0;
}
T2 Problem b
求:
∑
i
=
a
b
∑
j
=
c
d
[
g
c
d
(
i
,
j
)
=
k
]
\sum_{i=a}^b \sum_{j=c}^d [gcd(i,j)=k]
i=a∑bj=c∑d[gcd(i,j)=k]
这题跟上题一模一样,只是多了个容斥。
a
n
s
=
a
n
s
(
(
1
,
b
)
,
(
1
,
d
)
)
−
a
n
s
(
(
1
,
b
)
,
(
1
,
c
−
1
)
)
−
a
n
s
(
(
1
,
a
−
1
)
,
(
1
,
d
)
)
+
a
n
s
(
(
1
,
a
−
1
)
,
(
1
,
c
−
1
)
)
ans = ans((1,b),(1,d))−ans((1,b),(1,c−1))−ans((1,a−1),(1,d))+ans((1,a−1),(1,c−1))
ans=ans((1,b),(1,d))−ans((1,b),(1,c−1))−ans((1,a−1),(1,d))+ans((1,a−1),(1,c−1))
ACcode:
#include<bits/stdc++.h>
#define LL long long
#define N 50100
using namespace std;
int sum[N],ans;
int pr[N],tot = 0,mu[N],a,b,c,d,k;
bool pd[N];
void get_mu(int n)
{
pd[1] = true;
mu[1] = 1;
for(int i=2;i<=n;i++)
{
if( pd[i]==false )
{
pr[++tot] = i;
mu[i] = -1;
}
for(int j=1;j<=tot&&i*pr[j]<=n;j++)
{
pd[ i*pr[j] ] = true;
if( i%pr[j]==0 ) break;
else mu[ i*pr[j] ] = -mu[i];
}
}
for(int i=1;i<=n;i++) sum[i] = sum[i-1] + mu[i];
}
LL cal(int n,int m)
{
LL s = 0;
n /= k;
m /= k;
if( n>m ) swap(n,m);
for(int l=1,r;l<=n;l=r+1)
{
r = min( n/(n/l) , m/(m/l) );
s += (LL)(sum[r]-sum[l-1]) * (LL)(n/l) * (LL)(m/l);
}
return s;
}
void solve()
{
scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
ans = cal( b,d ) - cal( a-1,d ) - cal( b,c-1 ) + cal( a-1,c-1 );
printf("%d\n",ans);
}
int main()
{
int t;
cin>>t;
get_mu(50000);
while( t-- ) solve();
return 0;
}
T3 [国家集训队]Crash的数字表格
求:
∑
i
=
1
n
∑
j
=
1
m
l
c
m
(
i
,
j
)
\sum_{i=1}^n \sum_{j=1}^m lcm(i,j)
i=1∑nj=1∑mlcm(i,j)
解:
=
∑
i
=
1
n
∑
j
=
1
m
i
j
g
c
d
(
i
,
j
)
=
∑
d
=
1
n
∑
i
=
1
n
∑
j
=
1
m
i
j
d
[
g
c
d
(
i
,
j
)
=
d
]
=
∑
d
=
1
n
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
i
∗
j
∗
d
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
=
1
n
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
i
∗
j
∗
d
∑
x
∣
g
c
d
(
i
,
j
)
μ
(
x
)
=
∑
d
=
1
n
∑
x
=
1
⌊
n
d
⌋
μ
(
x
)
∗
x
2
∑
i
=
1
⌊
n
d
x
⌋
∑
j
=
1
⌊
m
d
x
⌋
i
∗
j
=
∑
d
=
1
n
∑
x
=
1
⌊
n
d
⌋
μ
(
x
)
∗
x
2
∗
⌊
n
d
x
⌋
(
1
+
⌊
n
d
x
⌋
)
2
∗
⌊
m
d
x
⌋
(
1
+
⌊
m
d
x
⌋
)
2
=\sum_{i=1}^n \sum_{j=1}^m \frac{ij}{gcd(i,j)} \\ =\sum_{d=1}^n\sum_{i=1}^n \sum_{j=1}^m\frac{ij}{d}[gcd(i,j)=d] \\ =\sum_{d=1}^n \sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor }\sum_{j=1}^{ \lfloor \frac{m}{d} \rfloor }i*j*d[gcd(i,j)=1] \\ =\sum_{d=1}^n \sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor }\sum_{j=1}^{ \lfloor \frac{m}{d} \rfloor }i*j*d\sum_{x|gcd(i,j)} \mu(x) \\ =\sum_{d=1}^n \sum_{x=1}^{ \lfloor \frac{n}{d} \rfloor } \mu(x)*x^2 \sum_{i=1}^{ \lfloor \frac{n}{dx} \rfloor } \sum_{j=1}^{ \lfloor \frac{m}{dx} \rfloor }i*j \\ =\sum_{d=1}^n \sum_{x=1}^{ \lfloor \frac{n}{d} \rfloor } \mu(x)*x^2 * \frac{\lfloor \frac{n}{dx} \rfloor(1+\lfloor \frac{n}{dx} \rfloor)}{2} *\frac{\lfloor \frac{m}{dx} \rfloor(1+\lfloor \frac{m}{dx} \rfloor)}{2}
=i=1∑nj=1∑mgcd(i,j)ij=d=1∑ni=1∑nj=1∑mdij[gcd(i,j)=d]=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗d[gcd(i,j)=1]=d=1∑ni=1∑⌊dn⌋j=1∑⌊dm⌋i∗j∗dx∣gcd(i,j)∑μ(x)=d=1∑nx=1∑⌊dn⌋μ(x)∗x2i=1∑⌊dxn⌋j=1∑⌊dxm⌋i∗j=d=1∑nx=1∑⌊dn⌋μ(x)∗x2∗2⌊dxn⌋(1+⌊dxn⌋)∗2⌊dxm⌋(1+⌊dxm⌋)
Accode:
#include<bits/stdc++.h>
#define LL long long
#define N 10010000
using namespace std;
const LL M = 20101009;
int pr[N],tot=0,mu[N];
LL sum[N];
bool pd[N];
void get_mu(int x)
{
pd[1] = false;
mu[1] = 1;
for(int i=2;i<=x;i++)
{
if( pd[i]==false )
{
tot++;
pr[tot] = i;
mu[i] = -1;
}
for(int j=1;j<=tot&&i*pr[j]<=x;j++)
{
pd[ i*pr[j] ] = true;
if( i%pr[j]==0 ) break;
mu[ i*pr[j] ] = -mu[i];
}
}
for(int i=1;i<=x;i++)
{
sum[i] = ( sum[i-1] + 1LL*i*i%M*mu[i]%M )%M;
}
}
LL cal(int x,int y)
{
return (1LL*x*(x+1)/2%M)*(1LL*y*(y+1)/2%M)%M;
}
LL func(int n,int m)
{
LL ans = 0;
for(int l=1,r;l<=n;l=r+1)
{
r = min( n/(n/l),m/(m/l) );
ans = ( ans + ( sum[r]-sum[l-1] )*cal(n/l,m/l)%M )%M;
}
ans = (ans%M+M)%M;
return ans;
}
void solve()
{
int n,m;
LL ans = 0;
scanf("%d %d",&n,&m);
if( n>m ) swap(n,m);
get_mu(n);
for(int l=1,r;l<=n;l=r+1)
{
r = min( n/(n/l) , m/(m/l) );
ans = ( ans + 1LL*( r-l+1 )*( r+l )/2%M * func(n/l,m/l)%M )%M;
}
ans = (ans+M)%M;
printf("%lld\n",ans);
}
int main()
{
solve();
return 0;
}