线性筛框架——(算数基本定理、约数个数)

这篇具有很好参考价值的文章主要介绍了线性筛框架——(算数基本定理、约数个数)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

算术基本定理

在算术基本定理中,若正整数 N N N被唯一分解为 N = P 1 c 1 P 2 c 2 … P m c m N=P_1^{c_1}P_2^{c_2}…P_m^{c_m} N=P1c1P2c2Pmcm,其中 c i c_i ci都是正整数, p i p_i pi都是质数,且满足 p 1 < p 2 < … < p m p_1<p_2<…<p_m p1<p2<<pm,则 N N N的正约数集合可写作: { P 1 b 1 P 2 b 2 … P m b m } \{P_1^{b_1}P_2^{b_2}…P_m^{b_m}\} {P1b1P2b2Pmbm},其中 0 ≤ b i ≤ c i 0\leq b_i\leq c_i 0bici

N N N的正约数个数为: ( c 1 + 1 ) ∗ ( c 2 + 1 ) ∗ … ∗ ( c m + 1 ) = ∏ i = 1 m ( c i + 1 ) (c_1+1)*(c_2+1)*…*(c_m+1)=\prod\limits_{i=1}^m(c_i+1) (c1+1)(c2+1)(cm+1)=i=1m(ci+1)

HDU 1492

题意:给出一个只包含质因数2,3,5,7的数,求其约数的个数

/*************************************************************************
        > File Name: 1492.c
        > Author: Luzelin
        > Mail: 2351767075@qq.com
        > Created Time: Wed Apr  7 20:27:46 2021
 ************************************************************************/

#include <stdio.h>

int main() {
    unsigned long long n;
    while (~scanf("%lld", &n) && n) {
        int a = 1, b = 1, c = 1, d = 1;
        while (n % 2 == 0)  ++a, n /= 2;
        while (n % 3 == 0)  ++b, n /= 3;
        while (n % 5 == 0)  ++c, n /= 5;
        while (n % 7 == 0)  ++d, n /= 7;
        printf("%d\n", a * b * c * d);
    }
    return 0;
}

约数个数

算术基本定理中,根据拆分后的素因子的指数,我们可以求出每个 N N N 的约数的个数。

根据这个式子,我们可以用线性筛去筛出当前 N N N 的约数个数。

筛的过程中,我们需要保存下最小素因子的个数

下面证明中

a n s [ i ] ans[i] ans[i] 表示 i i i 的约数个数

n u m [ i ] num[i] num[i] 表示 i i i 的最小素因子的个数

p r i m e [ i ] prime[i] prime[i] 表示 第 i i i 个素数

① 当前数是素数

这种情况我们很容易得到,当前的 a n s [ i ] = ( 1 + 1 ) = 2 ans[i] = (1+1) = 2 ans[i]=(1+1)=2

因为素数只有一个素因子(就是它本身),并且指数为 1 1 1

而最小素因子个数 n u m [ i ] = 1 num[i] = 1 num[i]=1

i   %   p r i m e [ j ]   ≠   0 i \ \%\ prime[j]\ \neq \ 0 i % prime[j] = 0

这种情况,我们可以知道 i i i 当中,并不包含 p r i m e [ j ] prime[j] prime[j] 这个素因子,然而, i ∗ p r i m e [ j ] i*prime[j] iprime[j] 中, 包含了一个 p r i m e [ j ] prime[j] prime[j]

而且由于 当前的 p r i m e [ j ] prime[j] prime[j] 必然是 i ∗ p r i m e [ j ] i*prime[j] iprime[j] 的最小素因子 (因为从小到大枚举啊!), 我们要记录下这个最小素因子的个数

所以保存一个数 n u m [ i ∗ p r i m e [ j ] ] = 1 num[i*prime[j]] = 1 num[iprime[j]]=1

我们可以从前面得到 i i i 的所有约数个数 ( 1 + a 1 ) ( 1 + a 2 ) … ( 1 + a n ) (1+a_1)(1+a_2)…(1+a_n) (1+a1)(1+a2)(1+an)

然后再补上 当前多了 素因子 p r i m e [ j ] prime[j] prime[j] 的因子个数 ( 1 + a 1 ) ( 1 + a 2 ) … ( 1 + a n ) ( 1 + 1 ) (1+a_1)(1+a_2)…(1+a_n)(1+1) (1+a1)(1+a2)(1+an)(1+1)

所以最后 a n s [ i ∗ p r i m e [ j ] ] = a n s [ i ] ∗ 2 ans[i * prime[j]] = ans[i] * 2 ans[iprime[j]]=ans[i]2

i   %   p r i m [ j ]   = =   0 i\ \%\ prim[j]\ ==\ 0 i % prim[j] == 0

这种情况, i i i 中必然包含了至少 1 个 p r i m e [ j ] prime[j] prime[j] ,而且 p r i m e [ j ] prime[j] prime[j] 也必定是 i i i 的最小素因子,因为每次枚举都是从小的素数开始枚举。

i ∗ p r i m e [ j ] i*prime[j] iprime[j] 比起 i i i 则是多了一个最小素因子个数,即 n u m [ i ∗ p r i m e [ j ] ] = n u m [ i ] + 1 num[i * prime[j]] = num[i] + 1 num[iprime[j]]=num[i]+1

i i i 的约数个数是 ( 1 + a 1 ) ( 1 + a 2 ) … ( 1 + a n ) (1+a_1)(1+a_2)…(1+a_n) (1+a1)(1+a2)(1+an)

那么 i ∗ p r i m e [ j ] i*prime[j] iprime[j] 的约数个数 应该是 ( 1 + a 1 + 1 ) ( 1 + a 2 ) … ( 1 + a n ) (1+a_1+1)(1+a_2)…(1+a_n) (1+a1+1)(1+a2)(1+an)

之后,我们就要用到我们之前记录下的最小素因子个数了,因为我们可以知道 i i i 的最小素因子个数 为 n u m [ i ] num[i] num[i] ,而 a n s [ i ] ans[i] ans[i] 中 已经包含了 ( 1 + a 1 ) ( 1 + a 2 ) … ( 1 + a n ) (1+a_1)(1+a_2)…(1+a_n) (1+a1)(1+a2)(1+an)这时我们可以除去第一项 1 + a 1 1+a_1 1+a1 然后乘以 1 + a 1 + 1 1+a_1+1 1+a1+1 ,就可以得到 a n s [ i ∗ p r i m e [ j ] ] ans[i*prime[j]] ans[iprime[j]] 的约数个数了。 a n s [ i ∗ p r i m e [ j ] ] = a n s [ i ] / ( n u m [ i ] + 1 ) ∗ ( n u m [ i ] + 2 ) ans[i * prime[j]] = ans[i] / (num[i] + 1) * (num[i] + 2) ans[iprime[j]]=ans[i]/(num[i]+1)(num[i]+2)

P1403约数研究
输入一个数n,输出1-n每个数约数的数量和

1   1
2   1 2
3   1 3
4   1 2 4
5   1 5
6   1 2 3 6

input 6
output 14
/*************************************************************************
        > File Name: P1403_1.cpp
        > Author: Luzelin
        > Mail: 2351767075@qq.com
        > Created Time: Fri Apr 29 09:29:54 2022
 ************************************************************************/

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e6;

int table[N + 5] = {1, 1}, prime[N + 5], t;
int min_fac_cnt[N + 5], ans[N + 5] = {0, 1};

void make_table() {
    for (int i = 2; i <= N; ++i) {
        if (table[i] == 0) {
            prime[t++] = i;
            min_fac_cnt[i] = 1;
            ans[i] = 2;
        }
        for (int j = 0; i * prime[j] <= N; ++j) {
            table[i * prime[j]] = 1;
            if (i % prime[j]) {
                min_fac_cnt[i * prime[j]] = 1;
                ans[i * prime[j]] = ans[i] * 2;
            } else {
                min_fac_cnt[i * prime[j]] = min_fac_cnt[i] + 1;
                ans[i * prime[j]] = ans[i] / (min_fac_cnt[i] + 1) * (min_fac_cnt[i] + 2);
                break;
            }
            // if (i % prime[j] == 0)  break;
        }
    }
    return ;
}

int main() {
    make_table();
    for (int i = 2; i <= N; ++i) {
        ans[i] += ans[i - 1];
    }
    int n;
    cin >> n;
    cout << ans[n] << endl;
    return 0;
}

优化空间版:文章来源地址https://www.toymoban.com/news/detail-403609.html

/*************************************************************************
        > File Name: P1403.cpp
        > Author: luzelin
        > Mail: luzelin1024@163.com
        > Created Time: Sun 30 Oct 2022 04:08:08 PM CST
 ************************************************************************/

#include <iostream>

using namespace std;

const int N = 1e6;

// fc : factor cnt    mfc : min factor cnt
int fc[N + 5] = {0, 1}, mfc[N + 5] = {1, 1}, table[N + 5];

void make_table(int n) {
    for (int i = 2; i <= n; ++i) {
        if (table[i] == 0) {
            table[++table[0]] = i;
            fc[i] = 2;
            mfc[i] = 1;
        }
        for (int j = 1; i * table[j] <= n; ++j) {
            table[i * table[j]] = 1;
            if (i % table[j]) {
                fc[i * table[j]] = fc[i] << 1;
                mfc[i * table[j]] = 1;
            } else {
                fc[i * table[j]] = fc[i] / (mfc[i] + 1) * (mfc[i] + 2);
                mfc[i * table[j]] = mfc[i] + 1;
                break;
            }
        }
    }
    return ;
}

int GetAns(int n) {
    make_table(n);
    for (int i = 2; i <= n; ++i)  fc[i] += fc[i - 1];
    return fc[n];
}

int main() {
    int n;
    cin >> n;
    cout << GetAns(n) << endl;
    return 0;
}

到了这里,关于线性筛框架——(算数基本定理、约数个数)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【考研数学】线性代数第六章 —— 二次型(2,基本定理及二次型标准化方法)

    了解了关于二次型的基本概念以及梳理了矩阵三大关系后,我们继续往后学习二次型的内容。 定理 1 —— (标准型定理)任何二次型 X T A X pmb{X}^Tpmb{AX} X T A X 总可以经过可逆的线性变换 X = P Y pmb{X=PY} X = P Y ,即 P pmb{P} P 为可逆矩阵,把二次型 f ( X ) f(pmb{X}) f ( X ) 化为标准

    2024年02月07日
    浏览(30)
  • [保研/考研机试] KY3 约数的个数 清华大学复试上机题 C++实现

    KY3 约数的个数 https://www.nowcoder.com/share/jump/437195121691716950188 输入n个整数,依次输出每个数的约数的个数 输入的第一行为N,即数组的个数(N=1000) 接下来的1行包括N个整数,其中每个数的范围为(1=Num=1000000000) 可能有多组输入数据,对于每组输入数据, 输出N行,其中每一行对应上

    2024年02月13日
    浏览(34)
  • OpenCV基本操作——算数操作

    两个图像应该具有相同的大小和类型,或者第二个图像可以是标量值 注意:OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加的是模运算 ((414, 500, 3), (429, 499, 3)) (429, 499, 3) 其实也是加法,只是权重不同

    2024年02月13日
    浏览(36)
  • FPGA基本算术运算

      FPGA相对于MCU有并行计算、算法效率较高等优势,但同样由于没有成型的 FPU 等MCU内含的浮点数运算模块,导致一些基本的符号数、浮点数运算需要我们自己进行管理。因此需要我们对基本的运算法则进行了解。基本类别如下,即:    无符号数即为没有符号的数,简单

    2024年02月09日
    浏览(27)
  • 【线性代数】P3 拉普拉斯定理

    拉普拉斯定理是通过对余子式和代数余子式的变形展开得到,有关余子式和代数余子式的概念见:https://blog.csdn.net/weixin_43098506/article/details/126765390 假设有四阶行列式: k阶子式 行列式D的一个二阶子式为: 余子式 那么二阶子式A的余子式为: 代数余子式 那么二阶子式的代数余

    2024年02月12日
    浏览(34)
  • 线性代数矩阵秩的8大性质、重要定理以及关系

             

    2024年02月11日
    浏览(33)
  • 【电路理论】KCL、KVL、线性直流电路各大方法、定理详解

    博主简介: 努力学习的22级计科生一枚~ 博主主页: @是瑶瑶子啦 所属专栏: 电路理论 💡 注意 分析对象:电路中某一节点 用处:找出电流之间的关系,列方程,求解未知量 注意电流的参考方向 核心:节点相连支路:流入节点电流 = 流出节点电流 💡 注意 :对于含n个节点、

    2024年02月10日
    浏览(30)
  • LA@2@1@线性方程组和简单矩阵方程有解判定定理

    线性方程组有解判定 线性方程组 A x = b Abold{x}=bold{b} A x = b 有解的 充分必要条件是它的系数矩阵A和增广矩阵 ( A , b ) (A,bold{b}) ( A , b ) 具有相同的秩 R ( A ) = R ( A , b ) R(A)=R(A,bold{b}) R ( A ) = R ( A , b ) ,记 r = R ( A ) = R ( A , b ) r=R(A)=R(A,bold{b}) r = R ( A ) = R ( A , b ) : 若 r = n r=n r = n 有

    2024年02月12日
    浏览(30)
  • 【线性代数】P3 行列式按行展开&异乘变零定理

    将元素所在行与所在列去除剩余的“子式”,记为 M i j M_{ij} M ij ​ ,即去除第 i i i 行与第 j j j 列。 e . g . e.g. e . g . 有行列式如下,求 M 12 M_{12} M 12 ​ 与 M 23 M_{23} M 23 ​ 在余子式的基础上加上符号,记为 A i j A_{ij} A ij ​ ; e . g . e.g. e . g . 有行列式如下,求 A 12 A_{12} A 12

    2024年02月02日
    浏览(32)
  • <基础数学> 平面向量基本定理

    向量平行 a ⃗ / / b ⃗ ( b ⃗ ≠ 0 ⃗ )的充要条件是 vec{a} // vec{b}( vec{b}neq vec{0})的充要条件是 a // b ( b  = 0 )的充要条件是 x 1 y 2 − y 1 x 2 = 0 x_1y_2-y_1x_2=0 x 1 ​ y 2 ​ − y 1 ​ x 2 ​ = 0 向量垂直 a ⃗ ⊥ b ⃗ ⇔ a ⃗ ⋅ b ⃗ = 0 , vec{a} bot vec{b} Leftrightarrow vec{a}

    2024年04月26日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包