zoukankan      html  css  js  c++  java
  • 数论

      简单了解了一下数论,有些东西没弄懂,就纪录一下数论的简单知识,以备不时之需

      1 素数筛法

        (1)埃式筛法

          最简单思路:所有可能的因数全部试一遍。(特判1和2不是素数)

    void Init(int n)
    
    {
    
        memset(book,0,sizeof(book));
    
        book[0] = 1;
    
        book[1] = 1;
    
        for(int i = 2; i <= n; i++)
    
        {
    
            if(book[i]==0)
    
            {
    
                for(int j = i+i; j <= n; j += i)
    
                book[j] = 1;
        
            }
    
        }
    
    }
    

      (2)欧拉筛法(线性筛法)

    本代码保证每个合数只会被它的最小质因数筛去,因此每个数只会被标记一次,所以时间复杂度是O(n)

    #include<cstdio>
    #include<cstring>
    #define MAXN 100005
    #define MAXL 1299710
    int prime[MAXN];
    int check[MAXL];
    int tot = 0;
    memset(check, 0, sizeof(check));
    for (int i = 2; i < MAXL; ++i)
    {
        if(!check[i])prime[tot++] = i;
        for (int j = 0; j < tot&&i * prime[j] <= MAXL; ++j){
            check[i*prime[j]] = 1;
            if (i % prime[j] == 0)break;
        }
    }
    

      (3)区间筛素数

    思路:因为b以内合数的最小质因数一定不超过sqrt(b),如果有sqrt(b)以内的素数表的话,就可以把筛选法用在[a,b)上了,先分别做好[2,sqrt(b))的表和[a,b)的表,然后从[2,sqrt(b))的表中筛得素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是区间[a,b)内的素数了

    typedef long long ll;
    bool is_prime[maxn];
    bool is_prime_small[maxn];
    void segment_sieve(ll a,ll b) 
    {
         for(ll i=0;i*i<b;++i) is_prime_small[i]=true; //初始化
         for(ll i=0;i<b-a;++i) is_prime[i]=true; //初始化,注意下标变化,为了省空间
         for(ll i=2;i*i<b;++i) {
             if(is_prime_small[i]) {
                 for(ll j=2*i;j*j<b;j+=i) is_prime_small[j]=false;  //筛选[2,sqrt(b));
                 //(a+i-1)/i得到最接近a的i的倍数,最低是i的2倍,然后筛选
                 for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i) is_prime[j-a]=false;
             }
         }
    }
    

    2欧几里得

           (1)欧几里得算法 (Euclidean algorithm) ,即大部分选手所知的“辗转相除法”,用来求解最大公约数问题

    int gcd(int a, int b)   //欧几里得求最大公约数
    {
        if(b == 0) return a;
        return gcd(b, a%b);
    }

    int lcm(int a,int b){ //最小公倍数
    return a/gcd(a,b)*b; //防止溢出
    }

      (2)扩展欧几里得

           即ax + by = gcd(a,b);

    而当gcd(a,b) = 1,即a,b互质的时候,这个方程的解实际上就对应了a关于模b的逆元。
    下面是从欧几里得算法拓展的过程:
    首先呢,可以看出:a = gcd(a,b), b = 0 是该式的一个特解;
    然后,根据欧几里得算法的原理可以得出:bx + (a%b)y = gcd(a,b);
    又因为, a%b = a - (a/b)*b (a/b 为整除关系)
    所以原式化为: bx + (a - (a/b)*b)y = gcd(a,b);
    整理得: ay + b * (x - (a/b) * y) = gcd(a,b);
    所以解之间的递归关系为:
    - xx = y;
    - yy = x - (a/b)y;

    int extend_Euclid(int a, int b, int &x, int &y)
    {
        if(b==0)
        {
            x = 1;
            y = 0;
            return a;
        }
        int r = extend_Euclid(b, a%b, y, x);
        y -= a/b*x; //这里已经是递归,回溯的过程了,x,y已经颠倒了
        return r;
    }
    

      

        同时,可以给出通解的方程:

       x = x0 + b/gcd(a,b)*t;

       y = y0 - a/gcd(a,b)*t;

       (x0, y0 为方程的一组特解, t为整数)

    三.模与余:
    (1)模运算:
    1.取模运算:a % p(a mod p),表示a除以p的余数。
    2.模p加法:(a + b) % p = (a%p + b%p) % p
    3.模p减法:(a - b) % p = (a%p - b%p) % p
    4.模p乘法:(a * b) % p = ((a % p)*(b % p)) % p
    5.幂模p : (a^b) % p = ((a % p)^b) % p
    6.模运算满足结合律、交换律和分配律。
    7.a≡b (mod n) 表示a和b模n同余,即a和b除以n的余数相等。

    (2)同余的性质:
    1.反身性:a≡a (mod m);
    2.对称性:若a≡b(mod m),则b≡a (mod m);
    3.传递性:若a≡b(mod m),b≡c(mod m),则a≡c(mod m);
    4.同余式相加:若a≡b(mod m),c≡d(mod m),则a c≡b d(mod m);
    5.同余式相乘:若a≡b(mod m),c≡d(mod m),则ac≡bd(mod m)。
    (3)快速幂

    //快速幂求a^b; 
    #include<bits/stdc++.h>
    using namespace std;
    int k(int a,int b){
    	int t = 1;
    	while(b){
    		if(b%2 != 0){
    			t *= a;
    			b--;
    		}
    		a *= a;
    		b /= 2;
    	}
    	return t;
    }
    int main()
    {
    	int a,b;
    	scanf("%d%d",&a,&b);
    	int x = k(a,b);
    	cout<<x<<endl;
    	return 0; 
    }
    
    
    
    /*//快速幂求a^b的后y位; 
    #include<bits/stdc++.h>
    using namespace std;
    int k(int a,int b,int y){
    	int t = 1;
    	while(b){
    		if(b%2 != 0){
    			t = (a*t)%y;
    			b--;
    		}
    		a = (a*a)%y;
    		b /= 2;
    	}
    	return t;
    }
    int main()
    {
    	int a,b,y;
    	scanf("%d%d%d",&a,&b,&y);
    	int x = k(a,b,y);
    	cout<<x<<endl;
    }*/
    

      四.唯一分解定理

                题目链接:http://lightoj.com/login_main.php?url=volume_showproblem.php?problem=1341

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1000050;
    typedef long long ll;
    ll a[N],b[N],k = 0;
    ll init(ll n){
    	ll s = 1;
    	if(n == 0){
    		return 0;
    	}
    	ll tt = 0;
    	ll i = 0;
    	while(a[i] < n && i < k){
    		tt = 0;
    		if(n % a[i] == 0){
    			while(n % a[i] == 0){
    				n /= a[i];
    				tt++;
    			}
    		}
    		s *= tt+1;
    		i++; 
    	}
    	if(n > 1){
    		s *= 1+1;
    	}
    	return s;
    }
    int main()
    {
    	k = 0;
    	ll i = 0;
    	for( i = 2; i <= N; i++){
    		if(!b[i]){
    			a[k++] = i;
    			for(ll j = i+i; j <= N; j += i){
    				b[j] = 1;
    			}
    		}
    	}
    	int t;
    	scanf("%d",&t);
    	int h = 0;
    	while(t--){
    		h++;
    		ll n,m,num = 0,cns = 0;
    		scanf("%lld%lld",&n,&m);
    		if(m >= sqrt(n)){
    			num = 0;
    		}
    		else{
    			for(i = 1; i < m; i++){
    				if(n%i == 0){
    					cns++;
    				}
    			}
    			num = init(n)/2;
    			num -= cns;
    		}
    		printf("Case %d: %lld
    ",h,num);
    	}
    	return 0;
    }
    

      

    五.欧拉函数:
    5.1定义:
    互质:gcd(a,b)=1,则a,b互质
    欧拉函数φ(n):小于等于n的所有数中与n互质数的个数

    5.2性质:
    1.对于质数p, φ( p) = p - 1。注意φ(1)=1
    2. 若m,n互质,φ(mn)=φ(m)φ(n)
    3. 当n为奇数时,φ(2n)=φ(n)
    4.当n大于2时,所有φ(n)都是偶数
    5.当n大于6时,所有φ(n)都是合数

    6.欧拉定理:对于互质的正整数a和n,有a^φ(n) ≡ 1 mod n
    7.费马小定理:若gcd(a,b)=1,则a^(p-1)=1 mod n
    8.欧拉定理推论:小于等于n的数中,与n互质数的总和为:φ(n)*n/2 (n>1)

    //求一个数的欧拉函数
    //直接求解欧拉函数 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; }

      

    //求1-n每个数的欧拉函数
    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);//先进行除法是为了防止中间数据的溢出 }

      

  • 相关阅读:
    软件工程个人作业01
    学习进度一(2017/12/2)
    课程增加功能(java web)
    剑指offer-把数组排成最小的数
    论文-Edge Boxes
    论文-Selective Search
    剑指offer-机器人的运动范围
    leetcode-539-Minimum Time Difference
    Leetcode-543-Diameter of Binary Tree
    论文-SSD-Single Shot MultiBox Detector
  • 原文地址:https://www.cnblogs.com/clb123/p/10992792.html
Copyright © 2011-2022 走看看