• 素数专题


    素数是一个经常的涉及到得内容,所以有必要整理出有关解决素数相关问题的算法

    学习资料:Eratosthenes筛法和欧拉筛法对比  一般筛法求素数+快速线性筛法求素数  数学技巧之素数筛选

         素数与素性测试 〖数学算法〗素性测试  请看Miller-Rabin算法!  Miller-Rabin素数测试  Pollard-rho大整数分解

    1. 素数筛法

      代码1(埃氏筛法):

    /*
        埃氏筛法:返回n以内素数的个数, 复杂度O (nloglogn)
    */
    int seive(int n)    {        //Eratosthenes (埃氏筛法)
        int p = 0;
        memset (is_prime, true, sizeof (is_prime));
        is_prime[0] = is_prime[1] = false;
        for (int i=2; i<=n; ++i)    {
            if (is_prime[i])    {
                prime[++p] = i;
                for (int j=2*i; j<=n; j+=i)    is_prime[j] = false;
            }
        }
        return p;
    }
    

      代码2(欧拉筛法):

    /*
        欧拉筛法:返回n以内素数的个数, 复杂度O (n)
    */
    int seive(int n)    {        //Euler (欧拉筛法)
        int p = 0;
        memset (is_prime, true, sizeof (is_prime));
        is_prime[0] = is_prime[1] = false;
        for (int i=2; i<=n; ++i)    {
            if (is_prime[i])    prime[++p] = i;
            for (int j=1; j<=p && i*prime[j]<=n; ++j)    {
                is_prime[i*prime[j]] = false;
                if (i % prime[j] == 0)    break;
            }
        }
        return p;
    }

    附上比较两种筛法的测试结果(新标签查看原图)

    2. 素性测试

      代码1:

    /*
        素性测试,输入正数,复杂度O (sqrt(n))
    */
    bool is_prime(int n)    {
        for (int i=2; i*i<=n; ++i)  {
            if (n % i == 0)    return false;
        }
        return n != 1;    //1例外
    }
    

      代码2:

    /*
        素性测试,在小范围(1e5)内判素数个数以及单个数判素数有奇效,不适用于大范围判素数
    */
    bool is_prime(int x)    {
        if (x == 2 || x == 3)   return true;
        if (x % 6 != 1 && x % 6 != 5)   return false;
        for (int i=5; i*i<=x; i+=6) {
            if (x % i == 0 || x % (i + 2) == 0) return false;
        }
        return true;
    }
    

      代码3(Miller_Rabin 随机算法):

    /*
    	素性测试,Miller_Rabin 随机算法
    	可以判断< 2^63的数
    	素数:true,合数:false
    */
    const int S = 20;									//随机算法判定次数,S越大,判错概率越小
    
    //非递归写法,递归写法可能会爆栈
    ll GCD(ll a, ll b)	{
    	if (a == 0)	return 1;
    	if (a < 0)	a = -a;
    	while (b)	{
    		ll c = a % b;
    		a = b; b = c;
    	}
    	return a;
    }
    
    //计算 (a * b) % p,a,b是long long数,直接相乘可能会溢出
    ll multi_mod(ll a, ll b, ll p)	{
    	ll ret = 0;
    	a %= p;	b %= p;
    	while (b)	{
    		if (b & 1)	{
    			ret += a;
    			if (ret >= p)	ret -= p;
    		}
    		a <<= 1;
    		if (a >= p)	a -= p;
    		b >>= 1;
    	}
    	return ret;
    }
    
    //计算 a ^ x % p
    ll pow_mod(ll a, ll x, ll p)	{
    	ll ret = 1;
    	a %= p;
    	while (x)	{
    		if (x & 1)	ret = multi_mod (ret, a, p);
    		a = multi_mod (a, a, p);
    		x >>= 1;
    	}
    	return ret;
    }
    
    /*
    	以a为基,n-1=x*2^t,a^(n-1) = 1(mod n)  验证n是不是合数
    	一定是合数返回true, 不一定返回false
    */
    bool check(ll a, ll n, ll x, int t)	{
    	ll ret = pow_mod (a, x, n);
    	ll last = ret;
    	for (int i=1; i<=t; ++i)	{
    		ret = multi_mod (ret, ret, n);
    		if (ret == 1 && last != 1 && last != n - 1)	return true;	//合数
    		last = ret;
    	}
    	if (ret != 1)	return true;
    	return false;
    }
    
    bool Miller_Rabin(ll n)	{
    	if (n == 2)	return true;
    	if (n < 2 || ! (n & 1))	return false;			//偶数或1
    	ll x = n - 1;	int t = 0;
    	while (! (x & 1))	{
    		x >>= 1;	t++;
    	}
    	for (int i=1; i<=S; ++i)	{
    		ll a = rand () % (n - 1) + 1;				//需要cstdlib头文件
    		if (check (a, n, x, t))	return false;		//合数
    	}
    	return true;
    }
    

      

     3. 整数分解

      代码1:

    /*
        整数分解,试除法进行质因子分解,复杂度O(sqrt(n))
    */
    map<int, int> factorize(int n)   {
        map<int, int> res;
        for (int i=2; i*i<=n; ++i)  {
            while (n % i == 0)    {
                ++res[i];    n /= i;
            }
        }
        if (n != 1)    res[n] = 1;
        return res;
    }
    

      代码2:

    /*
        整数分解,先打个素数表优化试除法
    */
    vector<int> factorize(int n)  {
        int p = seive (100000);
        vector<int> ret;
        for (int i=1; i<=p && prime[i]<=n/prime[i]; ++i)    {
            while (n % prime[i] == 0)  {
                n /= prime[i];
                ret.push_back (prime[i]);
            }
        }
        if (n != 1) ret.push_back (n);
        return ret;
    }
    

      代码3(Pollard_rho 随机算法):

    /*
    	大整数分解,Pollard_rho 随机算法
    	factorize ()保存质因数在vector
    */
    ll Pollard_rho(ll x, ll c)	{
    	ll i = 1, k = 2;
    	ll a = rand () % x;
    	ll b = a;
    	while (1)	{
    		i++;
    		a = (multi_mod (a, a, x) + c) % x;
    		ll d = GCD (b - a, x);
    		if (d != 1 && d != x)	return d;
    		if (b == a)	return x;
    		if (i == k)	b = a, k += k;
    	}
    }
    
    void factorize(ll n, vector<ll> &ret)	{			//ret保存质因数,无序
    	if (Miller_Rabin (n))	{						//素数
    		ret.push_back (n);	return ;
    	}
    	ll p = n;
    	while (p >= n)	p = Pollard_rho (p, rand () % (n - 1) + 1);
    	factorize (p, ret);
    	factorize (n / p, ret);
    }
    
    
    int main(void)    {
    	srand (time (NULL));							//需添加ctime头文件
    	int T;	scanf ("%d", &T);
    	while (T--)	{
    		ll n;	scanf ("%I64d", &n);
    		if (Miller_Rabin (n))	puts ("Prime");
    		else	{
    			if (n <= 1)	{							//1的情况特判,否则RE
    				puts ("-1");	continue;
    			}
    			vector<ll> ans;
    			factorize (n, ans);
    			sort (ans.begin (), ans.end ());
    			for (int i=0; i<ans.size (); ++i)	{
    				printf ("%I64d%c", ans[i], (i == ans.size ()-1) ? '
    ' : ' ');
    			}
    		}
    	}
    	
        return 0;
    }

      

    其他:

      代码:

    /*
        约数枚举,复杂度O (sqrt(n))
    */
    vector<int> divisor(int n)  {
        vector<int> ret;
        for (int i=1; i*i<=n; ++i)  {
            if (n % i == 0) {
                ret.push_back (i);
                if (n / i != i)    ret.push_back (n / i);
            }
        }
        return res;
    }
    编译人生,运行世界!
  • 相关阅读:
    word2vec的Java源码【转】
    将博客搬至CSDN
    去掉中英文符号
    搜索引擎原理和简单过程【转】
    写国际会议论文和期刊的一些注意事项
    Java中Map根据键值(key)或者值(value)进行排序实现
    solr 查询获取数量getCount()
    【solr filter 介绍--转】http://blog.csdn.net/jiangchao858/article/details/54989025
    将中文数字转为数字
    java.util.Properties类的介绍-配置文件的读写【-Z-】
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4736142.html
Copyright © 2020-2023  润新知