2019暑训8月14号 数论
作者:互联网
数论
重要的数论函数:
ε(n), 1(n), id(n), μ(n), φ(n), τ(n)
Dirichlet卷积
Dirichlet 卷积学习笔记-露迭月 感觉这篇博客讲的比较通透、系统。
由此还寻找到了另一篇讲的很好的dirichlet卷积的博客 铃悬的数学小讲堂——狄利克雷卷积与莫比乌斯反演
事实上,单从mobius的表达式来看它实在是太突兀了,我们应该在dirichlet卷积的角度下认识这个函数。“dirichlet卷积与数论函数共同构成了群”,而群具有逆元与幺元,这里的幺元很自然的就是1,那么我们就定义mobius函数是1的逆,也就是μ * 1 = ε,之后通过尝试构造可以得到mobius函数的表达式。
下面介绍几个常见的卷积:
φ * 1(n) = id(n)
定理证明:
等式两边再卷上1的逆——μ后可得: φ(n) = id * μ(n)
τ(n) = 1 * 1(n)
根据定义这是显然的。
等式两边卷上1的逆后可得: 1(n) = μ * τ(n)
mobius函数还有一些性质,这篇博客(Mobius函数)对其中的三个(mobius是积性函数、mobius的表达式、φ(n) = id * μ(n))进行了干净漂亮的说明。
Mobius反演:
根据“逆”这一重要概念,我们可以方便地得到mobius反演的结论:
形式1(约数反演):若F(n) = f * 1(n),则f(n) = F * μ(n)
形式2(倍数反演):若F(n) = Σf(d)[n \ d] = Σf(i * d),则f(n) = Σμ(d / n)F(d)[n \ d]
素数筛法
1.线性筛(欧拉筛)
int prime[maxn];
int visit[maxn];
void Prime(){
mem(visit,0);
mem(prime, 0);
for (int i = 2;i <= maxn; i++) {
if (!visit[i]) {
prime[++prime[0]] = i; //纪录素数, 这个prime[0] 相当于 cnt,用来计数
}
for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
}
欧拉筛保证每个数只被最小素因子筛一遍,所以其时间复杂度约为线性的。
昨天晚上CF遇到个1e6的筛法我忘记了以前在vj哪里写过euler筛了…找自己的博客想了半天发现好像是没有整理…
2.杜教筛
参见博客 杜教筛
推导过程省略,直接贴上最终的恒等式关系。我们的目的就是寻找一个恰当的函数g(n)可以使得h(n) = f * g(n)是一个容易求前缀和的函数,后面的式子则通过数论分块的办法来求和即可。
下面我们看一个杜教筛的模版: 洛谷P4213 杜教筛
很容易可以根据mobius反演确定出杜教筛中的g(n) = 1(n),接下来就是求解与优化的问题了。
(1)在线筛的同时可以线性的求解欧拉函数与mobius函数的值,代码如下:
其中,行52的公式是基于这样的事实:i是prime[j]的倍数,那么用定义求该i * prime[j]的欧拉函数时,prime[j]拥有的素因子一定也被i拥有,所以prime[j]在该定义式中仅仅起到系数的作用,素因子只需要考虑i即可。
(2)用无序map<int, ll>记录Σf(n),预处理ll sump[maxn]、sum[maxn]。maxn开太小会TLE,找一个合适的maxn(比如5e6)可以AC。
(3)注意到n最大可能取到0x7fffffff,这个时候如果指针i指向j + 1,极有可能会爆到一个负数上,所以我们需要对这种情况进行一个特判!
标签:prime,函数,卷积,反演,2019,mobius,maxn,暑训,14 来源: https://blog.csdn.net/Herr_Shiiiii/article/details/99550679