• 两个有关素数的算法


    Miller_Rabin算法(素数判定)

    作用

    单独判断一个大数是否素数。缺点他是一个不保证正确的算法,我们只能通过多次执行算法让这个错误的概率很小,不过幸运的是通常来看它的错误概率可以小到忽略不计。

    补充:【模板】素数测试(Miller-Rabin测试)

    算法的理论基础

    1. Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n−1),则 a^(n-1) ≡ 1 mod n。
    2. 推演自Fermat定理, 如果n是一个奇素数,将n−1表示成2^s*r的形式,r是奇数,a与n是互素的任何随机整数,那么a^r ≡ 1 mod n或者对某个j (0 ≤ j≤ s−1, j∈Z) 等式a^(2jr) ≡ −1 mod n 成立。

    代码实现

     1 bool Miller_Rabin(ll n)//Miller_Rabin算法,判断n是否为素数
     2 {
     3     if(n<2) return false;
     4     if(n==2) return true;
     5     if(!(n&1)) return false;
     6     ll r=n-1,s=0;
     7     while(!(r&1)){r=r>>1;s++;}
     8     for(ll i=0;i<NUM;i++)
     9     {
    10         ll a=rand()%(n-1)+1;
    11         if(check(a,n,r,s))
    12             return false;
    13     }
    14     return true;
    15 }

    Pollard_rho算法

    作用

    求一个数的因子

    原理

    设n为待分解的大整数,用某种方法生成a和b,计算p=gcd(a-b,n),直到p不为1或a,b出现循环时为止,若p=n,则说明n是一个素数,否则p为n的一个约数。

    算法步骤

    选取一个小的随机数x1,迭代生成x[i] = x[i-1]^2+c,一般取c=1,若序列出现循环则退出,计算p=gcd(x[i-1]-x[i],n),若p=1则返回上一步继续迭代,否则跳出迭代过程。若p=n,则n为素数,否则p为n的一个约数,并递归分解p和n/p。

    可以在θ(sqrt(p))的期望时间内找到n的一个小因子p。但对于因子很少,因子值很大的大整数n,该方法依然不是很有效。

    为了减少反复的次数,算法做了一些改进。该算法用数对(x0,x0)开始,并且用x(i+1)=f(xi) ,迭代计算(x1,x2),(x2,x4),(x3,x6)…(xi,x2i)。在每一次迭代中,我们都应用上述函数式运算(从第二步)第一次计算数对中的第一个元素,第二次计算数对中的第二个元素。

    代码实现

     1 ll Pollard_rho(ll n,ll c)//Pollard_rho算法,找出n的因子
     2 {
     3     ll i=1,j,k=2,d,p;
     4     ll x=rand()%n;
     5     ll y=x;
     6     while(true)
     7     {
     8         i++;
     9         x=(mul_mod(x,x,n)+c)%n;
    10         if(y==x) return n;
    11         if(y>x) p=y-x;
    12         else p=x-y;
    13         d=gcd(p,n);
    14         if(d!=1&&d!=n) return d;
    15         if(i==k)
    16         {
    17             y=x;
    18             k+=k;
    19         }
    20     }
    21 }
    22 void find(ll n)//找出n的所有因子
    23 {
    24     if(Miller_Rabin(n))
    25     {
    26         f[t++]=n;//保存所有因子
    27         return;
    28     }
    29     ll p=n;
    30     while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);//由于p必定为合数,所以通过多次求解必定能求得答案
    31     find(p);
    32     find(n/p);
    33 }

    因数个数求解公式

    对于任何一个自然数N,都可以分解质因子得到如下形式:

    N=pe11pe22pe33···pekkN=p1e1∗p2e2∗p3e3∗···∗pkek

    那么,N的因子的个数为:

    f(n)=(1+e1)(1+e2)···(1+ek)f(n)=(1+e1)∗(1+e2)∗···∗(1+ek)

    如N=100,分解质因子变形为:100=22∗52,N的因子的个数为:f(N)=f(100)=(1+2)∗(1+2)=9。

    即:1,2,4,5,10,20,25,50,100。

    一些函数

    头文件&宏定义

    1 #include<bits/stdc++.h>
    2 using namespace std;
    3 #define ll long long
    4 const ll NUM=10;//运算次数,Miller_Rabin算法为概率运算,误判率为2^(-NUM);
    5 ll t,f[100];

    快速乘法、快速幂函数

     1 ll mul_mod(ll a,ll b,ll n)//求a*b%n,由于a和b太大,需要用进位乘法
     2 {
     3     a=a%n;
     4     b=b%n;
     5     ll s=0;
     6     while(b)
     7     {
     8         if(b&1)
     9             s=(s+a)%n;
    10         a=(a<<1)%n;
    11         b=b>>1;
    12     }
    13     return s;
    14 }
    15 ll pow_mod(ll a,ll b,ll n)//求a^b%n
    16 {
    17     a=a%n;
    18     ll s=1;
    19     while(b)
    20     {
    21         if(b&1)
    22             s=mul_mod(s,a,n);
    23         a=mul_mod(a,a,n);
    24         b=b>>1;
    25     }
    26     return s;
    27 }
    28 bool check(ll a,ll n,ll r,ll s)
    29 {
    30     ll ans=pow_mod(a,r,n);
    31     ll p=ans;
    32     for(ll i=1;i<=s;i++)
    33     {
    34         ans=mul_mod(ans,ans,n);
    35         if(ans==1&&p!=1&&p!=n-1)
    36             return true;
    37         p=ans;
    38     }
    39     if(ans!=1) return true;
    40     return false;
    41 }
    42 
    43 ll gcd(ll a,ll b)
    44 {
    45     return b==0?a:gcd(b,a%b);
    46 }

    求因数个数时主函数

     1 int main()
     2 {
     3     srand(time(NULL));//随机数设定种子
     4     ll n;cin>>n;
     5     if(n==1){cout<<"1"<<endl;return 0;}
     6     t=0;
     7     find(n);
     8     sort(f,f+t);
     9     map<ll,int>q;
    10     for(int i=0;i<t;i++)
    11     {
    12         q[f[i]]++;
    13     }
    14     map<ll,int>::iterator it;
    15     ll ans=1;
    16     for(it=q.begin();it!=q.end();it++)
    17     {
    18         int s=it->second;
    19         ans*=1+s;
    20     }
    21     cout<<ans<<endl;
    22     return 0;
    23 }
     
  • 相关阅读:
    Jquery(智能感知AJAX,从后台调数据)
    jQuery插件(输入关键字出现提示,并可查询)
    设置缓存失效的三种方法
    关于fluorinefx基础和服务器搭建的文章地址
    关于过河问题的感悟
    .net 大文件上传
    iis7中运行cmd
    学习总结
    C#开源资源项目(转载)
    HTML数据提取
  • 原文地址:https://www.cnblogs.com/duny31030/p/14304123.html
Copyright © 2020-2023  润新知