1. 程式人生 > >pollard_rho(大數質因子分解)

pollard_rho(大數質因子分解)

大佬部落格
運用大素數判斷和隨機化演算法來找尋一個因子,而可以遞迴求出所有的因子。
poj 1811
題意:判斷一個數是不是素數,是的話輸出prime否則的話輸出這個數的最小素因子。

#include<cstdio>
#include<cstring>
#include<ctime>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
int cont;
LL factor[200
];//分解結果(返回結果是無序的) static int S=3;//規定隨機多少次,次數越多正確率越高 LL quick_mod_multi(LL a,LL b,LL mod)//快速求a*b%mod { LL t=0; a%=mod; while(b) { if(b&1) { t+=a; if(t>=mod)//取模要比減法慢的多 t-=mod; } a<<=1; if(a>=mod) a-=mod; b>>=1
; } return t; } LL quick_mod_power(LL a,LL b,LL mod)//快速求a^b%mod { LL res=1; a%=mod; while(b) { if(b&1) res=quick_mod_multi(res,a,mod); b>>=1; a=quick_mod_multi(a,a,mod); } return res; } bool miller_rabbin(LL n)//素性檢驗 { if
(n==2) return true; if(n<2||!(n&1)) return false; int t=0; LL a,x,y,u=n-1; while((u&1)==0) t++,u>>=1; for(int i=0; i<S; i++) //隨機多少次 { a=rand()%(n-1)+1; x=quick_mod_power(a,u,n); for(int j=0; j<t; j++) { y=quick_mod_multi(x,x,n); if(y==1&&x!=1&&x!=n-1) return false; x=y; } if(x!=1) return false; } return true; } LL get_gcd(LL a,LL b) { if(a==0) return 1; if(a<0) return get_gcd(-a,b); while(b) { LL t=a%b; a=b; b=t; } return a; } LL pollard_rho(LL n,LL c) { LL i=1,k=2,x,y; x=rand()%n; y=x; while(1) { i++; x=(quick_mod_multi(x,x,n)+c)%n; LL d=get_gcd(y-x,n); if(d>1&&d<n) return d; if(y==x) return n; if(i==k) { y=x; k<<=1; } } } void findfac(LL n)//找n的素因子 { if(n==1) return ; if(miller_rabbin(n)) { factor[cont++]=n; return ; } LL p=n; while(p>=n) p=pollard_rho(p,rand()%(n-1)+1); findfac(p); findfac(n/p); } int main() { srand((unsigned)time(NULL));//poj 上有這個會RE int ncase; scanf("%d",&ncase); while(ncase--) { LL n; scanf("%lld",&n); if(miller_rabbin(n)) printf("Prime\n"); else { cont=0; findfac(n); LL ans=factor[0]; for(int i=0; i<cont; i++) ans=min(ans,factor[i]); printf("%lld\n",ans); } } }

hdu 4344
題意:給出一個長為n(n小於2^63)的管子,現在要在管子上做標記,每隔L個長度單位做一個標記,從管子頭端開始,保證最後一次標記恰好在管子的尾端。讓你找出有多少個這樣的L(n>L),且他們之間兩兩互素,然後求出這些L的和最大值。
思路:首先可以想到L肯定是n的因子,還要所有互素的因子,只需要找到所有的素因子,統計一下相同的素因子有多少個,假如有k個則不相同的素因子的k次方肯定是互素的,加起來就好了。還要注意只有一個因子的時候這個時候k次冪就是自己本身,所以求的是k-1次冪;

#include<cstdio>
#include<cstring>
#include<ctime>
#include<map>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
int cont;
LL factor[200];//分解結果(返回結果是無序的)
static int S=3;//規定隨機多少次,次數越多正確率越高
LL quick_mod_multi(LL a,LL b,LL mod)//快速求a*b%mod
{
    LL t=0;
    a%=mod;
    while(b)
    {
        if(b&1)
        {
            t+=a;
            if(t>=mod)//取模要比減法慢的多
                t-=mod;
        }
        a<<=1;
        if(a>=mod) a-=mod;
        b>>=1;
    }
    return t;
}
LL quick_mod_power(LL a,LL b,LL mod)//快速求a^b%mod
{
    LL res=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            res=quick_mod_multi(res,a,mod);
        b>>=1;
        a=quick_mod_multi(a,a,mod);
    }
    return res;
}
bool miller_rabbin(LL n)//素性檢驗
{
    if(n==2) return true;
    if(n<2||!(n&1)) return false;
    int t=0;
    LL a,x,y,u=n-1;
    while((u&1)==0) t++,u>>=1;
    for(int i=0; i<S; i++) //隨機多少次
    {
        a=rand()%(n-1)+1;
        x=quick_mod_power(a,u,n);
        for(int j=0; j<t; j++)
        {
            y=quick_mod_multi(x,x,n);
            if(y==1&&x!=1&&x!=n-1)
                return false;
            x=y;
        }
        if(x!=1) return false;
    }
    return true;
}
LL get_gcd(LL a,LL b)
{
    if(a==0) return 1;
    if(a<0) return get_gcd(-a,b);
    while(b)
    {
        LL t=a%b;
        a=b;
        b=t;
    }
    return a;
}
LL pollard_rho(LL n,LL c)
{
    LL i=1,k=2,x,y;
    x=rand()%n;
    y=x;
    while(1)
    {
        i++;
        x=(quick_mod_multi(x,x,n)+c)%n;
        LL d=get_gcd(y-x,n);
        if(d>1&&d<n) return d;
        if(y==x) return n;
        if(i==k)
        {
            y=x;
            k<<=1;
        }
    }
}
void findfac(LL n)//找n的素因子
{
    if(n==1) return ;
    if(miller_rabbin(n))
    {
        factor[cont++]=n;
        return ;
    }
    LL p=n;
    while(p>=n)
        p=pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}
int main()
{
    srand((unsigned)time(NULL));
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        LL n;
        scanf("%lld",&n);
        if(miller_rabbin(n)) printf("Prime\n");
        else
        {
            cont=0;
            findfac(n);
            map<LL,LL> mp;
            for(int i=0; i<cont; i++)
            {
                if(mp[factor[i]]==0)
                    mp[factor[i]]=factor[i];
                else
                    mp[factor[i]]*=factor[i];
            }
            LL ans=0;
            map<LL,LL>::iterator it;
            for(it=mp.begin(); it!=mp.end(); it++)
                ans+=(it->second);
            if(mp.size()==1)
                ans/=factor[0];
            printf("%d %lld\n",mp.size(),ans);
        }
    }
}