一、数论函数的定义
数论函数指定义域为正整数集的函数
二、积性函数与完全积性函数
2.1 数论函数的定义
对于一个数论函数
f
(
x
)
f(x)
f(x) 满足
f
(
a
b
)
=
f
(
a
)
×
f
(
b
)
f(ab) = f(a) × f(b)
f(ab)=f(a)×f(b),则称
f
(
x
)
f(x)
f(x) 为一个积性函数
若 ∀ a , b ∈ Z + ∀ a,b ∈ Z+ ∀a,b∈Z+,都有 f ( a b ) = f ( a ) × f ( b ) f(ab) = f(a) × f(b) f(ab)=f(a)×f(b),则称 f ( x ) f(x) f(x) 是一个完全积性函数
2.2 积性函数的性质
若
f
(
x
)
f(x)
f(x) 是一个积性函数,且
x
x
x 的唯一分解式为
x
=
p
1
c
1
p
2
c
2
…
p
k
c
k
x= p_1^{c_1} p_2^{c_2}…p_k^{c_k}
x=p1c1p2c2…pkck,则
f
(
x
)
=
f(x) =
f(x)=
∏
i
=
1
k
\prod_{i=1}^k
∏i=1k
f
(
p
i
c
i
)
f(p_i^{c_i})
f(pici)
对于证明,显然每一项之间互质,于是按照积性函数的定义即可证明
注意这个性质是 f(x) 是积性函数的充要条件
三、简单的常见数论函数
3.1 欧拉函数
设 ϕ ( x ) ϕ(x) ϕ(x) 为在模 x 域下的简化剩余系大小,称为欧拉函数,显然欧拉函数是一个数论函数。并且欧拉函数是一个积性函数。
证明我不会
3.2 幺元函数
幺元函数 e ( x ) = [ x = 1 ] e(x) = [x = 1] e(x)=[x=1]我们约定中括号返回一个布尔量,中括号内表达式为真返回1,否则返回0
3.3 常函数 1
常函数 o n e ( x ) = 1 one(x) = 1 one(x)=1。不管自变量如何取值函数值恒为 1
3.4 标号函数
标号函数 I d ( x ) = x Id(x) = x Id(x)=x。即返回自变量本身
3.5 除数函数
σ ( k , x ) = ∑ d ∣ x d k σ(k,x) = ∑d∣xdk σ(k,x)=∑d∣xdk
当 k = 1 时,该函数表示 x 的因子之和
当 k = 0 时,该函数表示 x 的因子个数。
当 k 省略时默认为 1
容易证明上面五个函数都是积性函数,除第一个和第五个外都是完全积性函数
四、莫比乌斯函数
暂时略过
五、狄利克雷卷积
5.1 狄利克雷卷积的定义
设 f f f 和 g g g 都是数论函数,定义 f f f 和 g g g 的狄利克雷卷积为 h,记为 h = f ∗ g h = f∗g h=f∗g
定义 h ( n ) = ∑ x ∗ y = n f ( x ) × g ( y ) h(n) = \sum_{x*y=n}f(x) × g(y) h(n)=∑x∗y=nf(x)×g(y)
显然狄利克雷卷积拥有交换律和结合律以及乘法对加法的分配律
这里介绍一下单位元
5.2 函数的积性
若 f f f 和 g g g 都是积性函数,则 h h h 为积性函数
证明:
5.3 对因数求和函数的可卷性 (重点)
若 g ( n ) = ∑ d ∣ n f ( d ) , 则 g = f ∗ o n e g(n) = \sum_{d∣n} f(d),则 g = f∗one g(n)=∑d∣nf(d),则g=f∗one。其中 o n e one one 为常函数 1
证明上,依照狄利克雷卷积的定义,等价于每一项都乘 1,对答案不产生影响。
这里要注意辨析一下与单位元卷积等于其本身
5.4 常见数论函数的狄利克雷卷积
5.4.1莫比乌斯函数
莫比乌斯函数的性质:
可以改写为
μ
μ
μ ∗
o
n
e
=
e
one = e
one=e
e 为幺元函数
5.4.2 除数函数与幂函数
5.4.3欧拉函数与恒等函数
5.5 关于分配率 结合律 交换律
5.6 狄利克雷逆元
需要指出,积性函数必然存在逆元(因为
f
(
1
)
=
1
f(1) = 1
f(1)=1 ),且逆元仍是积性函数。
5.7 狄利克雷卷积求法
对于卷积的第n项可以直接枚举约数,在 n \sqrt n n的时间内计算
但是对于狄利克雷卷积的前 n n n项
如果一项一项算的话就需要 n n n\sqrt n nn,但实际上可以优化
设
x
=
d
,
y
=
i
/
d
x=d,y=i/d
x=d,y=i/d分别枚举
x
,
y
x,y
x,y对于
h
[
x
∗
y
]
+
=
f
[
x
]
∗
g
[
y
]
h[x*y]+=f[x]*g[y]
h[x∗y]+=f[x]∗g[y]即可。
时间复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn)
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
h[i*j] = ( h[i*j] + g[j] * f[i] % qwq ) % qwq;
}
}
对于卷k次的还可以用快速幂优化
for(int i=1;i<=n;i++) t[i] = 1;
while( k )
{
if( k&1 )
{
tot++;
if( tot==1 )
{
for(int i=1;i<=n;i++) g[i] = t[i];
}
else
{
for(int i=1;i<=n;i++) now[i] = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
now[i*j] = ( now[i*j] + g[i] * t[j] % qwq ) % qwq;
}
}
for(int i=1;i<=n;i++) g[i] = now[i];
}
}
for(int i=1;i<=n;i++) now[i] = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
now[i*j] = ( now[i*j] + t[i] * t[j] % qwq ) % qwq;
}
}
for(int i=1;i<=n;i++) t[i] = now[i];
k>>=1;
}
例题1:Longge 的问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
LL n,ans,sq;
LL phi(LL x)
{
LL y = x;
for(LL i=2;i<=sq;i++)
{
if( x%i==0 )
{
y = y / i * (i-1);
while( x%i==0 ) x /= i;
}
}
if( x>1 ) y = y / x * (x-1);
return y;
}
void solve()
{
scanf("%lld",&n);
sq = sqrt(n);
for(LL i=1;i<=sq;i++)
{
if( n%i==0 )
{
ans += i*phi( n/i );
if( i*i<n )
{
ans += (n/i) * phi( i );
}
}
}
printf("%lld\n",ans);
}
int main()
{
solve();
return 0;
}
例题2:jzoj【NOI2017模拟3.27】B
鉴于大家是进不去jzoj的
Input
Output
Sample Input
2
6 2
2 3 3 3 3 3
23 3
2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
Sample Output
2 7 7 15 7 23
2 9 9 24 9 39 9 50 24 39 9 102 9 39 39 90 9 102 9 102 39 39 9
idea:
ACcode:
#include<bits/stdc++.h>
#define LL long long
#define N 101000
#define LL long long
#define qwq 1000000007
using namespace std;
LL T,n,f[N],g[N],now[N],t[N],k,tot = 0;
void solve()
{
scanf("%lld %lld",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&f[i]);
for(int i=1;i<=n;i++) t[i] = g[i] = 1ll;
tot = 0;
while( k )
{
if( k&1 )
{
tot++;
if( tot==1 )
{
for(int i=1;i<=n;i++) g[i] = t[i];
}
else
{
for(int i=1;i<=n;i++) now[i] = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
now[i*j] = ( now[i*j] + g[i] * t[j] % qwq ) % qwq;
}
}
for(int i=1;i<=n;i++) g[i] = now[i];
}
}
for(int i=1;i<=n;i++) now[i] = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
now[i*j] = ( now[i*j] + t[i] * t[j] % qwq ) % qwq;
}
}
for(int i=1;i<=n;i++) t[i] = now[i];
k>>=1;
}
for(int i=1;i<=n;i++) now[i] = 0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n/i;j++)
{
now[i*j] = ( now[i*j] + g[j] * f[i] % qwq ) % qwq;
}
}
for(int i=1;i<=n;i++) printf("%lld ",now[i]);
printf("\n");
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
// freopen("in.txt","r",stdin);
// freopen("b.out","w",stdout);
cin>>T;
while( T-- )
{
solve();
}
return 0;
}