pollard_rho(大數質因子分解)
阿新 • • 發佈:2018-12-24
大佬部落格
運用大素數判斷和隨機化演算法來找尋一個因子,而可以遞迴求出所有的因子。
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);
}
}
}