寒假集训——基础数论3 炫酷的线筛及莫比乌斯函数,积性函数
积性函数
定义
积性函数:对于任意互质的整数a和b有性质 $ f(ab) = f(a) f(b) $ 的数论函数。
完全积性函数:对于任意整数a和b有性质 $ f(ab) = f(a) f(b) $ 的数论函数。
(以上出自百度百科)
性质
对于积性函数,有 $ f(1)=1 $
举例
$ φ(n) $-欧拉函数
$μ(n) $ -莫比乌斯函数,关于非平方数的质因子数目
$ gcd(n,k) $-最大公因子,当k固定的情况
$ d(n) $ -n的正因子数目
$ σ(n) $ -n的所有正因子之和
$ σk(n) $ - 因子函数,n的所有正因子的k次幂之和,当中k可为任何复数。
$ 1(n) $ -不变的函数,定义为 1(n) = 1 (完全积性)
$ Id(n) $ -单位函数,定义为 $ Id(n) = n $(完全积性)
$ Idk(n) $ -幂函数,对于任何复数、实数k,定义为 $ Idk(n) = n^k $(完全积性)
$ ε(n) $ -定义为:若n = 1,ε(n)=1;若 n > 1,ε(n)=0。别称为“对于狄利克雷卷积的乘法单位”(完全积性)
$ λ(n) $ -刘维尔函数,关于能整除n的质因子的数目
$ γ(n) $ ,定义为 $ γ(n)=(-1)^{ω(n)} $ ,在此加性函数 $ ω(n) $ 是不同能整除n的质数的数目
另外,所有狄利克雷特征均是完全积性的
(以上出自百度百科)
事实上讲积性函数是为了引出后面的线筛大法。
莫比乌斯函数
定义:
性质
1
积性函数
2
对于任意一个正整数n,都有

于2023。1.30补充
炫酷的线筛
我们先回顾普通的线筛
for1(i,2,n)
{
if(a[i] == 0)
ans[++ji] = i;
for(int j = 1;j <= ji && ans[j] *i <= n;j++)
{
a[ans[j] *i] = 1;
if(i % ans[j] == 0) break;
}
}
时间复杂度 $ O(n) $
于2023.1.18更新
我们再回看之前的线性筛求欧拉函数,不经沉思:

例子1
实践是检验真理的唯一标准,所以所以我们可以先拿刚学的莫比乌斯函数开刀,和欧拉函数的思考方法类似,此时枚举到了第i个数,此时在筛质因子p
- 质数,
- 最小质因数是p的数 ,
- 最小质因数不包含p的数,
简单易懂,写法也是差不多的。
for1(i,2,n)
{
if(a[i] == 0)
{
ans[++ji] = i;
mb[i]=-1;
}
for(int j = 1;j <= ji && ans[j] *i <= n;j++)
{
a[ans[j] *i] = 1;
if(i % ans[j] == 0)
{
mb[ans[j]*i]=0;
break;
}
else mb[ans[j]*i]=-mb[i];
}
}
于2023.1.30更新
例子2
再举一个例子,线性筛求约数个数函数
对于任意
有
很显然,这个也是积性函数,对于这样一个函数,尝试也线筛
首先对于第i个数,维护该数字的最小质因数的指数(即例子中的 $ a1 $ )cnt[i]
分类
- i为质数
- 包含最小质因子p的数,相当于最小质因子的指数+1
- 不包含最小质因子p的数,多了一个质因子,所以相当于乘2
代码实现:
for1(i,2,n)
{
if(a[i] == 0)
{
ans[++ji] = i;
d[i] = 2;
cnt[i] = 1;
}
for(int j = 1;j <= ji && ans[j] *i <= n;j++)
{
a[ans[j] *i] = 1;
if(i % ans[j] == 0)
{
d[ans[j]*i] = d[i] / (cnt[i] + 1) * (cnt[i] + 2);
cnt[i * ans[j]] = cnt[i] + 1;
break;
}
else
{
d[i * ans[j]] = d[i] * 2;
cnt[i * ans[j]] = 1;
}
}
}
总结

莫比乌斯反演
事实上莫比乌斯函数的用处似乎就是拿来做莫比乌斯反演(?),其他用处暂时没有看到
事实上这一段推导我也不知知道具体是什么意思,但是ppt上面写了,所以就搬下来了,实际上莫比乌斯反演的式子就是
就是推公式推导到这里时使用的。
应用 [HAOI2011]Problem b
懒得打了,具体就是这么推的

代码
#include<bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(int i = a;i <= b; i ++)
using namespace std;
const int maxn = 1e5 + 5;
int mb[maxn * 2],zs[maxn],cnt;
int sum[maxn * 2];
bool vis[maxn * 2];
int a, b, c, d, k;
void init(int n)
{
mb[1]=1;
for1(i,2,n)
{
if(vis[i] == 0)
{
zs[++cnt] = i;
mb[i] = -1;
}
for(int j = 1;j <= cnt && i * zs[j] <= n;j ++)
{
vis[i * zs[j]] = 1;
if(i % zs[j] == 0)
break;
else
mb[i * zs[j]] = -mb[i];
}
}
for1(i,1,n)
sum[i] = sum[i - 1] + mb[i];
}
ll cl(int a,int b)
{
int mx = min(a,b);
ll ans = 0;
for(int l=1,r;l<=mx;l=r+1)
{
r=min(a/(a/l),b/(b/l));
ans+=(1ll*a/(1ll*l*k))*(1ll*b/(1ll*l*k))*(sum[r]-sum[l-1]);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
init(50005);
while(T--)
{
cin >> a >> b >> c >> d >> k;
cout << cl(b ,d) - cl(b, c - 1) - cl(a - 1, d) + cl(a - 1,c - 1) << '\n';
}
return 0;
}
推广:


浙公网安备 33010602011771号