常用积性函数的线性筛法整理

简单整理推导加代码,留复习用。


线性筛素数

最简单也最基础,直接看代码就好了\(……\)

code:

void Euler_Phi_Prime(int n) {
    is_prime[1] = true;
    for (int i = 2; i <= n; i++) {
        if (!is_prime[i]) prime[++cnt] = i;
        for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
            is_prime[i * prime[j]] = true;
            if (i % prime[j] == 0) break;
        }
    }
}

线性筛欧拉函数

根据欧拉函数的两条性质\(:\)

  • 设\(p\)为素数,若\(p|n\)且\(p^2|n\),则\(\varphi(n)=\varphi(n/p)* p\)
  • 设\(p\)为素数,若\(p|n\)且\(p^2 \nshortmid n\),则\(\varphi(n)=\varphi(n/p)* (p-1)\)

对于第一条性质,若\(p|n\)且\(p^2|n\),那么显然\(n\)和\(n/p\)包含相同的质因子,并且将两者按照欧拉函数计算公式展开后只有\(p\)的指数不同,上下相除结果即为\(p\),故此性质成立。

对于第二条性质,若\(p|n\)且\(p^2 \nshortmid n\),说明\(n\)和\(n/p\)互质,根据欧拉函数为积性函数,我们显然可以得到\(\varphi(n)=\varphi(n/p) * \varphi(p)\),又因为\(\varphi(p)=p-1\),所以显然成立。

void Euler_Phi_Prime(int n) {
    phi[0] = phi[1] = 0;
    for (int i = 2; i <= n; i++) {
        if (!phi[i]) prime[++cnt] = i, phi[i] = i - 1;
        for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
            phi[i * prime[j]] = phi[i] * ((i % prime[j]) ? (prime[j] - 1) : prime[j]);
            if (i % prime[j] == 0) break;
        }
    }
}

线性求约数个数

考虑我们根据算数基本定理得到的推论之一:

一个正整数\(N\)的约数个数为:

\[d(N)=\prod_{i=1}^{m}(1+c_i)\]

在筛的过程中,我们记录\(N\)的最小素因子\(st[N]\)

我们根据筛素数分成三种情况考虑:

\(1.\)当前的数\(i\)为素数的时候,显然它只有\(1\)和自己两个因子且只有自己一个素因子,此时\(d(i)=2,\ st[i]=1\)

\(2.\)当\(i\) % \(prime[j]!=0\)时,显然\(i\)不包含\(prime[j]\)这个质因子,且\(prime[j]\)一定是\(i * prime[j]\)的最小质因子,因为我们是在从小到大枚举素数,这样\(i * prime[j]\)就相当于比\(i\)多了一个因子\(prime[j]\),那么\(i * prime[j]\)的约数和就为\(:\)

\[d(i * prime[j])=(1+c_1)(1+c_2)……(1+c_m)(1+1)\]

最后的\((1+1)\)即表示质因数分解后\(prime[j]\)的指数为\(1\),此时\(d(i * prime[j])=d(i) * d(prime[j])\) \(st[i * prime[j]]=1\).

\(3.\)当\(i\)%\(prime[j]==0\)时,显然\(i\)是包含\(prime[j]\)这个质因子的,\(i * prime[j]\)只是比\(i\)多了一个\(i\)的最小质因子,\((\)因为是从小到大枚举素数的\()\)即\(:\)

\[(i * prime[j])=(1+c_1+1)(1+c_2)……(1+c_m)\]

所以此时\(d(i * prime[j])=d(i) / (st[i] + 1) * (st[i] + 2)\) \(st[i * prime[j]]=st[i]+1\)

code:

void Euler_Phi_Prime(int n) {
    is_prime[1] = true, d[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!is_prime[i]) prime[++cnt] = i, d[i] = 2, st[i] = 1;
        for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
            is_prime[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                d[i * prime[j]] = d[i] / (st[i] + 1) * (st[i] + 2);
                st[i * prime[j]] = st[i] + 1; break;
            }
            d[i * prime[j]] = d[i] * d[prime[j]], st[i * prime[j]] = 1;
        }
    }
}

线性筛约数和

考虑算术基本定理的另一个推论\(:\)

一个正整数\(N\)的约数和为\(:\)

\[sd(N)=\prod_{i=1}^{m}{\large\lbrace}\sum_{j=0}^{c_i}(p_i)^j{\large\rbrace}\]

\[sd(N)=(1+p_1+p_1^2+
……+p_1^{c_1})(1+p_2+p_2^2+
……+p_2^{c_2})……(1+p_m+p_m^2+
……+p_m^{c_m})\]

筛的过程中我们记录\(st[i]=(1+p_i+p_i^2+ ……+p_i^{c_i})\)

仍旧按筛素数的情况分成三种情况考虑\(:\)

\(1.\)当当前的数\(i\)为质数时,显然\(i\)只有\(1\)和自己两个因子,显然\(sd[i]=st[i]=i+1\)

\(2.\)当\(i\)%\(prime[j]!=0\)时,显然\(i\)并不包含\(prime[j]\)这个质因子,且\(prime[j]\)一定是\(i * prime[j]\)的最小质因子,因为我们是在从小到大枚举素数,这样\(i * prime[j]\)就相当于比\(i\)多了一个因子\(prime[j]\),答案多累加上\(prime[j]\)的贡献即可\(:\)

\[sd(i* prime[j])=(1+p_1+p_1^2+
……+p_1^{c_1})……(1+p_m+p_m^2+
……+p_m^{c_m})(1+prime[j])\]

此时,\(sd[i* prime[j]]=sd[i] * sd[prime[j]],\ st[i* prime[j]]=prime[j]+1\)

\(3.\)当\(i\)%\(prime[j]==0\)时,显然\(i\)是包含\(prime[j]\)这个质因子的,\(i * prime[j]\)只是比\(i\)多了一个\(i\)的最小质因子,\((\)因为是从小到大枚举素数的\()\),所以\(i* prime[j]\)的约数和就表示为\(:\)

\[sd(i * prime[j])=(1+p_1+p_1^2+
……+p_1^{c_1}+p_1^{c_1+1})……(1+p_m+p_m^2+
……+p_m^{c_m})\]

此时,\(sd[i * prime[j]]=sd[i] / st[i] * (st[i] * prime[j]+1),\ st[i * prime[j]]=st[i]* prime[j]+1\)

code:

void Euler_Phi_Prime(int n) {
    is_prime[1] = true, sd[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!is_prime[i]) prime[++cnt] = i, sd[i] = i + 1, st[i] = i + 1;
        for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
            is_prime[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                sd[i * prime[j]] = sd[i] / st[i] * (st[i] * prime[j] + 1);
                st[i * prime[j]] = st[i] * prime[j] + 1; break;
            }
            sd[i * prime[j]] = sd[i] * sd[prime[j]], st[i * prime[j]] = prime[j] + 1;
        }
    }
}

线性筛莫比乌斯函数

窝太菜了,证明还是先鸽着吧\(……\)

code:

void Euler_phi(int n) {
    is_prime[1] = true, mu[1] = 1;
    for (int i = 2;  i <= n; i++) {
        if (!is_prime[i])
            prime[++cnt] = i, mu[i] = -1;
        for (int j = 1; j <= cnt && (i * prime[j]) <= n; j++) {
            is_prime[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
            mu[i * prime[j]] = -mu[i];
        }
    }
}

原文地址:https://www.cnblogs.com/Hydrogen-Helium/p/11737268.html

时间: 2024-09-29 08:34:09

常用积性函数的线性筛法整理的相关文章

积性函数,线性筛入门 HDU - 2879

HDU - 2879HeHe 题意:He[N]为[0,N−1]范围内有多少个数满足式子x2≡x (mod N),求HeHe[N]=He[1]×……×He[N] 我是通过打表发现的he[x]=2k,k为x是质因子个数,不过这是可以通过积性函数证明的. 关于积性函数的定义: 对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时,f(ab)=f(a)f(b),在数论上就称它为积性函数.若对于某积性函数 f(n) ,就算a, b不互质,也有f(ab)=f(a)f(b),则称它为完全积性

积性函数求和:筛法DP、洲阁筛

如果定义在正整数集上的函数 $f(n)$ 满足对于任意一对互素正整数 $n, m$ 都有 $f(n)f(m)=f(nm)$, 那么 $f$ 就叫做积性函数. 积性函数又可以表示为,假设 $n$ 的素因子分解式为 $n=\prod_{i=1}^mp_i^{c_i}$, 那么 $f(n)=\prod_{i=1}^mg(p_i, c_i)$. 本文讨论的函数满足:$g(p, c)$ 能够快速求单点值,且 $g(x, 1)$ 是关于 $x$ 的低次多项式. 积性函数求和,就是要求出 $\sum_{n=1

[常见积性函数的线性筛]【学习笔记】

[欧拉函数] φ(n)=n(1-1/p1)(1-1/p2)...(1-1/pk) 通过上式易发现 p[j]|i时 phi[i*p[j]]=phi[i]*p[j] 因为phi[i]的n是n*p[j]/p[j],其他的部分一样 证明:http://www.cnblogs.com/candy99/p/6200660.html void sieve(){ phi[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]){ p[++m]=i; phi[i]=i-1; } for(i

读贾志鹏《线性筛法与积性函数》笔记

1.欧拉筛法在线性时间内求素数以及欧拉函数 代码: 1 procedure get; 2 var i,j,k:longint; 3 begin 4 tot:=0; 5 fillchar(check,sizeof(check),false); 6 for i:=2 to n do 7 begin 8 if not(check[i]) then 9 begin 10 inc(tot); 11 p[tot]:=i; 12 fai[i]:=i-1; 13 end; 14 for j:=1 to tot

积性函数筛法

积性函数筛法 很多常用的数论函数都是积性函数,而在题目中,我们常常需要线性(甚至更高)的筛法. 对于积性函数,我们可以在筛素数的基础上稍加修改,即可完成线性筛. 首先,注意到积性函数的特点: \[ f(xy)=f(x)\times f(y) \] 而可以线性筛的积性函数,需要知道以下两个式子的快速求法: \[ f(p)=?\quad f(p^k)=?\\p\in prime \] 其中, \(f(p)\) 大多是直接定义,\(f(p^k)\) 大多是递归定义. 我们来回忆一下素数筛的过程: in

线性筛及其扩展-积性函数

线性筛 埃氏筛 对于每个数x,枚举其倍数,将kx筛去. 在埃氏筛过程中,每个数都会被筛掉多次,且对于每个数x,枚举其倍数的次数为\(\frac{n}{x}\) 故埃氏筛的时间复杂度为\(\sum_{i=1}^{n}\)\(\frac{n}{i}\)=n\(\sum_{i=1}^{n}\)\(\frac{1}{i}\)=\(n ln(n)\) 欧拉筛 在埃氏筛中,每个数会被筛掉多次,想要进一步下降复杂度,我们要求每个数只会被筛一次. 要想将多种筛去x的方法固定(唯一).我们就要采用一种方法-"最小

bzoj 2693: jzptab 线性筛积性函数

2693: jzptab Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 444  Solved: 174[Submit][Status][Discuss] Description Input 一个正整数T表示数据组数 接下来T行 每行两个正整数 表示N.M Output T行 每行一个整数 表示第i组数据的结果 Sample Input 1 4 5 Sample Output 122 HINT T <= 10000 N, M<=10000000

浅谈一类积性函数的前缀和(转载)

本文转自:http://blog.csdn.net/skywalkert/article/details/50500009 另外,莫比乌斯反演和杜教筛其他可转到 http://blog.leanote.com/post/totziens/%E8%8E%AB%E6%AF%94%E4%B9%8C%E6%96%AF%E5%8F%8D%E6%BC%94 写在前面 笔者在刷题过程中遇到一些求积性函数前缀和的问题,其中有一类问题需要在低于线性时间复杂度的算法,今天就来浅析一下这类问题的求解方法,当作以后讲课

POJ2480 Longge&#39;s problem 欧拉函数的应用 &amp;&amp; 积性函数

题意很简单,求sum(gcd(i,n))   1<=i<=n; 这题看到后第一反应并没有里用积性函数的性质,不过也可以做,欣慰的是我反应还是比较快的 设f(n)=gcd(1,n)+gcd(2,n)+....+gcd(n-1,n) + gcd(n,n), 用g(n,i)表示满足 gcd(x,n)=i的 x的个数 (x小于n),则 f(n)=sum{i*g(n,i)}; 同时又利用 扩展欧几里德的性质  gcd(x,n)=i  的充要条件是 gcd(x/i,n/i)==1,所以 满足 x/i的解有