测试地址:Prime Test
题目大意:给出
做法:这一题需要使用Miller-Rabin素数测试和Pollard-rho大数分解算法。
题如其名,思路题目中都告诉你了,先判断是不是素数,如果不是再找它的最小质因子。但是看到这个庞大的数据范围,就连判断素数这一个步骤,平常的筛法复杂度也是
我们知道费马小定理:如果
然而存在一种数,即使对于所有的
判断素数的问题解决了,接下来要找一个合数的最小质因子。对于这么大的数据范围,我们应该采用一种叫做Pollard-rho的大数分解算法,然后找到一个数的最小质因子(实际上,这个算法理论上可以在
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll T,N,minfactor,p[11]={2,3,5,7,11,13,17,19,23,29};
ll mult(ll a,ll b,ll mod) //计算a*b%mod
{
ll s=a,sum=0;
while(b)
{
if (b&1)
{
sum+=s;
if (sum>=mod) sum-=mod; //这里没有必要使用取模,取模运算比减法慢很多
}
b>>=1;s<<=1;if (s>=mod) s-=mod;
}
return sum;
}
ll power(ll a,ll b,ll mod) //计算a^b%mod
{
ll s=a,sum=1;
while(b)
{
if (b&1) sum=mult(sum,s,mod);
b>>=1;s=mult(s,s,mod);
}
return sum;
}
bool witness(ll n,ll a) //对整数n,底数a进行测试,返回1表示通过测试
{
ll p=power(a,n-1,n);
if (p!=1) return 0;
else
{
ll s=n-1;
while(!(s%2)&&p==1)
{
s>>=1;
p=power(a,s,n);
}
if (p==1||p==n-1) return 1;
else return 0;
}
}
bool miller_rabin(ll n) //对整数n进行Miller-Rabin素数测试,返回1表示通过测试
{
if (n<=29)
{
for(int i=0;i<10;i++)
if (n==p[i]) return 1;
return 0;
}
for(int i=0;i<10;i++)
if (!witness(n,p[i])) return 0;
return 1;
}
ll gcd(ll a,ll b) //Euclid算法计算a和b的最大公因数,很经典了
{
return (b==0)?a:gcd(b,a%b);
}
ll pollard_rho(ll n,ll c) //返回n的一个因子,如果返回n表示失败
{
ll x=rand()%n,y=x,d,i=1,k=2;
while(1)
{
i++;
x=(mult(x,x,n)+c)%n;
d=gcd(y-x+n,n);
if (d>1&&d<n) return d;
if (y==x) return n;
if (i==k) {y=x;k<<=1;}
}
}
void find_factor(ll n) //对整数n进行分解
{
if (miller_rabin(n))
{
minfactor=min(minfactor,n);
return;
}
ll p=n;
while(p>=n) p=pollard_rho(n,rand()%(n-1)+1);
find_factor(p);
find_factor(n/p);
}
int main()
{
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&N);
if (miller_rabin(N)) printf("Prime
");
else
{
minfactor=N;
find_factor(N);
printf("%lld
",minfactor);
}
}
return 0;
}