2019暑训8月14号 数论

拟墨画扇 提交于 2019-11-27 16:23:03

数论


重要的数论函数:
ε(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,极有可能会爆到一个负数上,所以我们需要对这种情况进行一个特判!

AC代码

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!