zoukankan      html  css  js  c++  java
  • 计蒜客 18487.Divisions-大数的所有因子个数-Miller_Rabin+Pollard_rho-超快的(大数质因解+因子个数求解公式) (German Collegiate Programming Contest 2015 ACM-ICPC Asia Training League 暑假第一阶段第三场 F)

    这一场两个和大数有关的题目,都用到了米勒拉宾算法,有点东西,备忘一下。

    题目传送门

    F. Divisions

    传送门

    这个题是求一个数的所有因子个数,但是数据比较大,1e18,所以是大数的题目,正常的求因数的或者求质因数的都过不了,因为这一场的K是米勒拉宾判大素数,先过的K题,所以这个题直接头铁用Miller_Rabin+Pollard_rho这两个东西+因子个数求解公式写过去了。

    这两个算法的具体原理不清楚。从别人那里知道了一点。

    Miller_Rabin算法的作用是判断一个数是否是个素数,算法速度很快,虽然是概率算法,有一定误判概率,不过可以多次运算大幅度减少误判,误判概率与运算次数t有关,为2^(-t);当t够大时,误判的可能性就很小了。

    Pollard_rho算法的作用是求一个数的因子,这个复杂度为O(sqrt(p)),p为这个数的因子。

    参考来自别的的博客,传送门:算法集锦(特殊模板集)

    因为Miller_Rabin+Pollard_rho这两个东西求出来的是一个数的所有质因数,所以最后要用因数个数求解公式来算出来结果。

    关于因数个数求解公式:

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

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

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

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

    特判一下1就可以,找出来素因子之后,我是用map记了一下数然后用因子个数求解公式得到的结果。其他的没什么了。

    代码:

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<iomanip>
      5 #include<stdio.h>
      6 #include<stdlib.h>
      7 #include<math.h>
      8 #include<cstdlib>
      9 #include<set>
     10 #include<map>
     11 #include<ctime>
     12 #include<stack>
     13 #include<queue>
     14 #include<vector>
     15 #include<set>
     16 using namespace std;
     17 typedef long long ll;
     18 const ll NUM=10;//运算次数,Miller_Rabin算法为概率运算,误判率为2^(-NUM);
     19 ll t,f[100];
     20 ll mul_mod(ll a,ll b,ll n)//求a*b%n,由于a和b太大,需要用进位乘法
     21 {
     22     a=a%n;
     23     b=b%n;
     24     ll s=0;
     25     while(b)
     26     {
     27         if(b&1)
     28             s=(s+a)%n;
     29         a=(a<<1)%n;
     30         b=b>>1;
     31     }
     32     return s;
     33 }
     34 ll pow_mod(ll a,ll b,ll n)//求a^b%n
     35 {
     36     a=a%n;
     37     ll s=1;
     38     while(b)
     39     {
     40         if(b&1)
     41             s=mul_mod(s,a,n);
     42         a=mul_mod(a,a,n);
     43         b=b>>1;
     44     }
     45     return s;
     46 }
     47 bool check(ll a,ll n,ll r,ll s)
     48 {
     49     ll ans=pow_mod(a,r,n);
     50     ll p=ans;
     51     for(ll i=1;i<=s;i++)
     52     {
     53         ans=mul_mod(ans,ans,n);
     54         if(ans==1&&p!=1&&p!=n-1)
     55             return true;
     56         p=ans;
     57     }
     58     if(ans!=1) return true;
     59     return false;
     60 }
     61 bool Miller_Rabin(ll n)//Miller_Rabin算法,判断n是否为素数
     62 {
     63     if(n<2) return false;
     64     if(n==2) return true;
     65     if(!(n&1)) return false;
     66     ll r=n-1,s=0;
     67     while(!(r&1)){r=r>>1;s++;}
     68     for(ll i=0;i<NUM;i++)
     69     {
     70         ll a=rand()%(n-1)+1;
     71         if(check(a,n,r,s))
     72             return false;
     73     }
     74     return true;
     75 }
     76 ll gcd(ll a,ll b)
     77 {
     78     return b==0?a:gcd(b,a%b);
     79 }
     80 ll Pollard_rho(ll n,ll c)//Pollard_rho算法,找出n的因子
     81 {
     82     ll i=1,j,k=2,d,p;
     83     ll x=rand()%n;
     84     ll y=x;
     85     while(true)
     86     {
     87         i++;
     88         x=(mul_mod(x,x,n)+c)%n;
     89         if(y==x) return n;
     90         if(y>x) p=y-x;
     91         else p=x-y;
     92         d=gcd(p,n);
     93         if(d!=1&&d!=n) return d;
     94         if(i==k)
     95         {
     96             y=x;
     97             k+=k;
     98         }
     99     }
    100 }
    101 void find(ll n)//找出n的所有因子
    102 {
    103     if(Miller_Rabin(n))
    104     {
    105         f[t++]=n;//保存所有因子
    106         return;
    107     }
    108     ll p=n;
    109     while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);//由于p必定为合数,所以通过多次求解必定能求得答案
    110     find(p);
    111     find(n/p);
    112 }
    113 int main()
    114 {
    115     srand(time(NULL));//随机数设定种子
    116     ll n;cin>>n;
    117     if(n==1){cout<<"1"<<endl;return 0;}
    118     t=0;
    119     find(n);
    120     sort(f,f+t);
    121     map<ll,int>q;
    122     for(int i=0;i<t;i++)
    123     {
    124         q[f[i]]++;
    125     }
    126     map<ll,int>::iterator it;
    127     ll ans=1;
    128     for(it=q.begin();it!=q.end();it++)
    129     {
    130         int s=it->second;
    131         ans*=1+s;
    132     }
    133     cout<<ans<<endl;
    134     return 0;
    135 }
  • 相关阅读:
    emulate sh
    postmaster.c 中的 ListenAddresses
    PostgreSQL的postmaster的fork动作验证
    NotifyMyFrontEnd 函数背后的数据缓冲区(三)
    对${ZSH_VERSION+set}的验证
    微软正准备一个简易的Rootkit清除方案 助用户打补丁 狼人:
    创新与安全:云计算的两只跷跷板 狼人:
    苹果禁止iPhone黑客访问App Store应用商店 狼人:
    春节不回家 单身留守族“拼饭”“拼玩” 狼人:
    僵尸侵入全球 袭击者或为东欧黑帮 狼人:
  • 原文地址:https://www.cnblogs.com/ZERO-/p/9302169.html
Copyright © 2011-2022 走看看