狄利克雷卷积
数论函数
数论函数是指一类函数,其定义域是正整数,值域是一个数集
积性函数都是数论函数
常见的数论函数有
- 单位函数,完全积性函数
- 元函数,完全积性函数
- 约数个数,积性函数
- 约数和函数,积性函数
- 莫比乌斯函数,积性函数
- 欧拉函数,积性函数
狄利克雷卷积
定义两个数论函数的狄利克雷卷积为 :
若
则
在狄利克雷卷积中
- 单位元是
- 若 则我们称 为 的逆元
一些应用
莫比乌斯反演
我们先来证明一点莫比乌斯反演里面的东西
很明显,化成卷积的形式即为
然后我们来证明莫比乌斯反演
显然可以化为
等式成立,展开后得到
得证
欧拉函数与莫比乌斯函数
已知
显然
展开得
除于得
(然后你可以用这个式子证明已知的公式)(证明证明证明)
杜教筛
杜教筛用于在小于线性的时间求一个积性函数的前缀和
即 求
为积性函数
为了愉快得求出这个式子我们需要设
和 均为积性函数
记 为 前缀和
然后Let's do it!
让我们做一点微小的改变
显然
除法分块 + 递归处理
只要你得前缀和能在大约左右得时间求出来(预处理后也可以的)时间复杂度就是
为什么?反正我是不会QAQ
来吧,上模板
Luogu P4213 【模板】杜教筛(Sum)
题目
莫比乌斯函数
众所周知
的前缀和过于显然——
没什么说的了
欧拉函数
众所周知
的前缀和…等差数列了解一下
没什么说的了
代码
#include <cstdio>
const int N = 2e6 + 10;
int T, n;
int sum_mu[N], sum_mu2[3400];
int mu[N], phi[N], pri[N], pcnt;
int has_phi[3400], has_mu[3400];
long long sum_phi[N], sum_phi2[3400];
bool vis[N];
void pre(){
vis[1] = true; mu[1] = 1; phi[1] = 1;
sum_mu[1] = sum_phi[1] = 1;
for(int i = 2; i < N; i++){
if(vis[i] == false){
pri[ ++pcnt ] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for(int j = 1; j <= pcnt; j++){
int tmp = pri[j] * i;
if(tmp >= N)
break;
vis[tmp] = true;
if(i % pri[j] == 0){
mu[tmp] = 0;
phi[tmp] = phi[i] * pri[j];
break;
}
mu[tmp] = -mu[i];
phi[tmp] = phi[i] * (pri[j] - 1);
}
sum_mu[i] = sum_mu[i - 1] + mu[i];
sum_phi[i] = sum_phi[i - 1] + (long long)phi[i];
}
}
long long ask_phi(int x){
if(x < N) return sum_phi[x];
int tmp = n / x;
if(has_phi[tmp] == n)
return sum_phi2[tmp];
has_phi[tmp] = n;
long long &ans = sum_phi2[tmp];
ans = (1LL * (1LL + x) * x) / 2;
for(int left = 2, rig; left <= x; left = rig + 1){
rig = x / (x / left);
ans -= (rig - left + 1) * ask_phi(x / left);
}
return ans;
}
int ask_mu(int x){
if(x < N) return sum_mu[x];
int tmp = n / x;
if(has_mu[tmp] == n)
return sum_mu2[tmp];
has_mu[tmp] = n;
int &ans = sum_mu2[tmp];
ans = 1;
for(int left = 2, rig; left <= x; left = rig + 1){
rig = x / (x / left);
ans -= (rig - left + 1) * ask_mu(x / left);
}
return ans;
}
int main(){
#ifdef woshiluo
freopen("luogu.4213.in", "r", stdin);
freopen("luogu.4213.out", "w" ,stdout);
#endif
pre();
scanf("%d", &T);
while(T--){
scanf("%d", &n);
printf("%lld %d\n", ask_phi(n), ask_mu(n));
}
fclose(stdin);
fclose(stdout);
}