• 数论——素数


    转自:http://www.cnblogs.com/linyujun/p/5198832.html

    整合:https://blog.csdn.net/x_i_y_u_e/article/details/46365549

    整合:https://blog.csdn.net/qq_43332305/article/details/82959066

    说明

    1. π(x) ,素数分布函数,为小于等于 x 的素数的个数。
    2. 当 x 趋于 无穷大时,π(x) 与 x / lnx等价。
    3. 当 x 趋于 无穷大时,1~x 中所有素数的倒数和与 $ln ln x$ 等价。
    4. factor(x) 表示x的因子个数,比如 factor(6) = 4。

    素数

    定义

    除了1和它本身以外不再有其他的因数的数。也叫质数。

    素数判定

    根据素数的定义判定(复杂度$O(sqrt{n})$)

    代码如下

    1 //素数
    2 inline bool isPrime(const LL x) {
    3     if (x <= 1)return false;
    4     for (LL i = 2; i * i <= x; i++)if (x % i == 0)return false;
    5     return true;
    6 }
    View Code

    埃拉托斯特尼筛法

    原理:如果找到一个质数,那么这个质数的倍数都不是质数。

    这个方法能在 $O(n ln ln n)$ 的时间复杂度内筛选出 1~n 中的所有素数。示例图如下:

    埃拉托色尼筛法图示

    复杂度说明如下

    设 pi 为 1~n 中第 i 个素数。

    对于每一个 pi,都要筛去 n / pi 个数,因此,筛选行为总数为 n * (1/p1 + 1/p2 +……+ 1/pπ(n)) ,等价于 $nln ln n$。

    代码如下

     1 bool primes[maxN];
     2 inline void Eratosthenes(){
     3     For(i, 2, maxN) primes[i] = true;//先全部初始化为质数 
     4     For(i, 2, maxN) {
     5         if(primes[i]){//如果i是质数 
     6             for(int j = 2 * i; j < maxN; j += i){//从i的两倍开始的所有倍数 
     7                 primes[j] = false; 
     8             }
     9         }
    10     }
    11 }
    View Code

    这个代码还能进一步优化,一个合数如果有因数,那么必定是成对存在,也就是筛子只用判断其中一个因数就可以了,比如15=3*5,在3的时候已经把15给筛掉了,何必去循环到5呢?循环到根号 n 即可。

    第二层循环中,j 可以从 i * i开始,因为 i * (i - 1), i * (i - 2) 等等这些数必然已经被比 i 小的质数筛掉了。

    代码如下(优化后)

     1 bool primes[maxN];
     2 inline void Eratosthenes(){
     3     For(i, 2, maxN) primes[i] = true;//先全部初始化为质数 
     4     for(int i = 2; i * i < maxN; ++i) {
     5         if(primes[i]){//如果i是质数 
     6             //从i * i开始的所有倍数
     7             for(int j = i * i; j < maxN; j += i){
     8                 primes[j] = false; 
     9             }
    10         }
    11     }
    12 }
    View Code

    线性筛法(欧拉筛法

    以空间换时间的方法,一个数只会经过一次,能把时间复杂度降为 O(n)。

    代码如下

     1 const int N = 1000;
     2 bool isPrime[N + 7];//isPrime[i]表示i是不是质数 
     3 VI primes;//primes用来存质数 
     4 inline void Euler(){
     5     For(i, 2, N) isPrime[i] = true;//初始化为质数 
     6     For(i, 2, N) {
     7         if(isPrime[i]) primes.PB(i);//把质数存起来 
     8         for(int j = 0; j < primes.size() && i * primes[j] <= N; ++j) {
     9             isPrime[i * primes[j]] = false;
    10             if(i % primes[j] == 0) break;//保证每个合数被它最小的质因数筛去 
    11         }
    12     }    
    13 }
    View Code

    算术基本定理

    定义

    任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积。当然 N 为质数的时候就是本身,没必要分解。

    设 N 的质因子为:p1, p2, ……,pπ(N)。(从小到大排)

    设对应质因子个数为:e1, e2, ……,eπ(N)

    则定义的公式表示为:$$N = prod_{i=1}^{π(N)} {p_i}^{e_i}$$

    约数个数定理

    $$factor(N) = prod_{i=1}^{π(N)} {e_i + 1}$$

    反素数

    定义

    对${forall_{0 < i < n}}$ ,都有 factor(n) > factor(i),称 n 为反素数。

    性质

    1. 一个反素数的质因子必然是从2开始连续的质数。
    2. 分解质因数后对应质因子的个数满足:e1 >= e2 >=……>= eπ(n)

     求不大于 n 的最大反素数代码

     1 LL n;
     2 // ans = (最大反素数,相应因子数) 
     3 PLL ans;
     4 int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
     5 
     6 // x 表示当前处理到第 x 个质数
     7 // ret为当前选择下的质数乘积 
     8 // pcnt 为 1~x-1 个质数中,每个质数选择数量+1的乘积 
     9 // limit 表示第x个质数选则的上限 
    10 // cnt表示第 x 个质数已经选了多少个 
    11 inline void dfs(int x = 0, LL ret = 1, LL pcnt = 1, int limit = inf, int cnt = 0) {
    12     if(ret > n || limit < cnt) return;
    13     LL tmp = pcnt * (cnt + 1);
    14     if(ans.sd < tmp || ans.sd == tmp && ans.ft > ret) ans = MP(ret, tmp);
    15     
    16     if(n / ret >= primes[x])dfs(x, ret * primes[x], pcnt, limit, cnt + 1); // 选 primes[x]
    17     if(cnt) dfs(x + 1, ret, tmp, cnt, 0); // 不选 primes[x]
    18 }
    View Code
  • 相关阅读:
    js上移、下移排序 效果
    如何为平板打造完美的网站页面?
    [BUUOJ]刮开有奖reverse
    [0CTF 2016]piapiapia
    [TSCTFJ 2019]bypass
    [安洵杯 2019]easy_serialize_php
    [TSCTFJ] relax
    c#访问网页
    DNN 数据访问
    c#访问数据库
  • 原文地址:https://www.cnblogs.com/zaq19970105/p/10799564.html
Copyright © 2020-2023  润新知