zoukankan      html  css  js  c++  java
  • 数论

    数论

    根号算法

    bool isprime(int x)
    {
        if(x==0||x==1) return 0;
        if(x==2) return 1;
        for(int i=3;i<=sqrt(x);i++)
        {
            if(x%i==0) return 0;
        } 
        return 1;
    } 
    
    • 单次时间复杂度:(O(sqrt x))
    • 判断1-n的素数个数:(O(xsqrt x))

    埃氏筛法

    • 先将2到n范围内的整数列出来,其中2是最小的素数。
    • 将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。
    • 再将表中所有的3的倍数划去……以此类推;
    • 如果表中剩余的最小的数是m,那么m就是素数。
    • 然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数。
    2 3 4 5 ... 13 14 15 16 17 18 19 20
    2 3 - 5 ... 13 - 15 - 17 - 19 -
    2 3 - 5 ... 13 - - - 17 - 19 -
    • 时间复杂度为(O(nlog(logn)))

    例:给定一个正整数n(n<=10^6),问n以内有多少个素数?

    int prime[MAXN];//第i个素数
    bool is_pri[MAXN+10];//is_pri[i]表示i是素数
    //返回n以内素数的个数
    int sieve(int n)
    {
        int p=0;
        for(int i=0;i<=n;i++) is_pri[i]=true;
        is_pri[0]=is_pri[1]=false;
        for(int i=2; i<=n; i++)
        {
            if(is_pri[i])
            {
                prime[++p]=i;
                for(int j=2*i; j<=n; j+=i) is_pri[j]=false;
            }
        }
        return p;
    }
    

    区间素数筛:给定两个正整数(a,b(a<bleq 10^{12},b-aleq 10^6)),请问[a,b)内有多少个素数?

    #include<iostream>
    using namespace std;
    bool pri[1000000+10];
    bool ispri[10000000+10];//ispri[i-a]=true代表i是素数
    void getpri()
    {
        memset(pri,true,sizeof(pri));
        pri[0]=pri[1]=0;
        for(int i=2;i<=1000000;i++)
        {
            if(pri[i]){
                for(int j=2*i;j<=1000000;j+=i)pri[j]=0;
            }
        }
    }
    int main(){
        long long a,b;
        scanf("%lld%lld",&a,&b);
        getpri();
        memset(ispri,true,sizeof(ispri));
        for(long long i=2;i*i<b;i++)
        {
            if(pri[i])
            {
                for(long long j=max((a+i-1)/i,2LL)*i;j<b;j+=i)
                    ispri[j-a]=0;
            }
        }
        long long cnt=0;
        for(int i=0;i<b-a;i++)if(ispri[i])cnt++;
        if(a==1)cnt--;
        printf("%lld
    ",cnt);
    }
    

    欧拉

    欧拉筛

    • 欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。
    int prime[maxn];
    int visit[maxn];
    void Prime()
    {
        mem(visit,0);
        mem(prime, 0);
        for (int i = 2;i <= maxn; i++) 
        {
            cout<<" i = "<<i<<endl;
            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;
            }
        }
    }
    
    • 上面有一个visit[i*prime[j]] = 1;,这里解释一下
      • 这里不是用i的倍数来消去合数,而是把prime里面纪录的素数,升序来当做要消去合数的最小素因子。
      • i是在消去合数中的作用是当做倍数的。
    • 还有一个i % prime[j] == 0
      • 当 i是prime[j]的倍数时,i=kprime[j],如果继续运算j+1,i * prime[j+1]=prime[j] * kprime[j+1],这里prime[j]是最小的素因子,当i=k * prime[j+1]时会重复,所以才跳出循环。
      • 举个例子 i=8,j=1,prime[j]=2,如果不跳出循环,prime[j+1]=3,83=243=212,在i=12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
      • 附上欧拉筛代码:
    /*求小于等于n的素数的个数*/
    #include<stdio.h>
    #include<string.h>
    using namespace std;
    int main()
    {
        int n, cnt = 0;
        int prime[100001];//存素数 
        bool vis[100001];//保证不做素数的倍数 
        scanf("%d", &n);
        memset(vis, false, sizeof(vis));//初始化 
        memset(prime, 0, sizeof(prime));
        for(int i = 2; i <= n; i++)
        {
            if(!vis[i])//不是目前找到的素数的倍数 
            prime[cnt++] = i;//找到素数~ 
            for(int j = 0; j<cnt && i*prime[j]<=n; j++)
            {
                vis[i*prime[j]] = true;//找到的素数的倍数不访问 
                if(i % prime[j] == 0) break;//关键!!!! 
            }
        }
        printf("%d
    ", cnt);
        return 0;
    }
    

    欧拉函数

    • 欧拉函数(φ(x))的值为在[1,x)的区间内与x互质的数的个数
    • 通式:(φ(x)=prod_{i=1}^xn(1−frac{1}{p_i})其中p_1,p_2,...,p_n)为x的所有质因数,x是不为0的整数。(φ(1)=1)
    • 注意:每种质因数只一个。比如(12=2×2×3)那么(φ(12)=12×(1−frac{1}{2})×(1−frac {1}{3})=4)
    • 介绍几个性质:
      • 若n是质数p的k次幂,则(φ(x)=p^k−p^{k−1}=(p−1)p^{k−1}),因为除了p的倍数外,其他数都跟n互质。
      • 积性函数——若m,n互质,(φ(mn)=φ(m)φ(n))
      • 当n为质数时,(φ(2x)=φ(x)),其实与上述类似。
      • 若n为质数则(φ(x)=x−1),这个挺重要的。
      • 一个数的所有质因子之和S是(S=frac {nφ(n)}{2})
    //用通式算的
    int euler(int n){ //返回euler(n)
        int res=n,a=n;
        for(int i=2;i*i<=a;i++){
            if(a%i==0){
                res=res/i*(i-1);//先进行除法是为了防止中间数据的溢出
                while(a%i==0) a/=i;
            }
        }
        if(a>1) res=res/a*(a-1);
        return res;
    }
    
    //筛选法打欧拉函数表
    #define Max 1000001
    int euler[Max];
    void Init()
    {
         euler[1]=1;
         for(int i=2;i<Max;i++) euler[i]=i;
         for(int i=2;i<Max;i++) if(euler[i]==i)
               for(int j=i;j<Max;j+=i)
                    euler[j]=euler[j]/i*(i-1);//先进行除法是为了防止中间数据的溢出
    }
    
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define N 100000
    int primes[N], euler[N], cnt;
    bool st[N];
    /* 欧拉函数
    可以在 O(n) 的时间复杂度内求出 1~n中所有数的欧拉函数 同时也能算质数
    质数存在primes[]中(用cnt统计<=n的素数个数),euler[i] 表示 i的欧拉函数*/
    int get_eulers(int n) 
    {
        euler[1] = 1;
        for (int i = 2; i <= n; i ++ ) 
        {
            if (!st[i]) 
            {
                primes[cnt ++ ] = i;
                euler[i] = i - 1;
            }
            for (int j = 0; j < cnt && i * primes[j] <= n; j ++ ) 
            {
                st[primes[j] * i] = true;
                if (i % primes[j] == 0) 
                {
                    euler[i * primes[j]] = euler[i] * primes[j];
                    break;
                }
                euler[i * primes[j]] = euler[i] * (primes[j] - 1);
            }
        }
        return cnt;
    }
     
    int main(void) 
    {
        get_eulers(101);
        for (int i = 0 ; i < cnt; i++) 
        {
            cout << i << " " << primes[i] << endl;
        }
        cout << endl;
        // 输出1到100每个数的欧拉函数值
        for (int j = 1 ; j < 101; j++) 
        {
            cout << j << " " << euler[j] << endl;
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    MYSQL 数据库管理
    maven初学总结
    解决问题的思路
    java泛型综述
    几种不常用的排序算法
    创新思维
    Django从入门到放弃
    KlayGE 4.0中Deferred Rendering的改进(二):拥挤的GBuffer
    用Android NDK r6编译boost 1.47
    glloader移植到了Android
  • 原文地址:https://www.cnblogs.com/orange-233/p/12258765.html
Copyright © 2011-2022 走看看