这道题没有看上去那么简单,需要用miller_rabin判断是否是素数,再用Pollard_Rho分解因数(求出其中最小的)。这两个算法都不是很好写。无数次WA, TLE后我最终还是用了这里的程序:http://www.cnblogs.com/ybrbupt/archive/2011/09/02/2164020.html。
可以直接移步上述链接,一些实现细节我也没看到,感觉虽然大家实现的都是同一个算法,写法却五花八门。
thestoryofsnow | 1811 | Accepted | 156K | 782MS | C++ |
/*
ID: thestor1
LANG: C++
TASK: poj1811
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
// see http://www.cnblogs.com/ybrbupt/archive/2011/09/02/2164020.html
typedef unsigned long long ULL;
#define gcc 10007
#define MAX ((ULL)1<<63)-1
using namespace std;
ULL p[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
inline ULL gcd(ULL a, ULL b)
{
ULL r = 1;
if(!b)
{
return a;
}
while(r)
{
r = a % b;
a = b;
b = r;
}
return a;
}
//计算a*b % mod
inline ULL multi_mod(ULL a, ULL b, ULL mod)
{
ULL sum = 0;
while(b)
{
if (b & 1)
{
sum = (sum + a) % mod;
}
a = (a + a) % mod;
b >>= 1;
}
return sum;
}
//计算a^b%n;
inline ULL quickmod(ULL a, ULL b, ULL mod)
{
ULL sum = 1;
while(b)
{
if(b & 1)
{
sum = multi_mod(sum, a, mod);
}
a = multi_mod(a, a, mod);
b >>= 1;
}
return sum;
}
// see https://www.topcoder.com/community/data-science/data-science-tutorials/primality-testing-non-deterministic-algorithms/
bool miller_rabin(ULL n)
{
int i, j, k = 0;
ULL u, m, buf;
//将n - 1分解为 m*2^k
if(n == 2)
{
return true;
}
if (n < 2 || !(n & 1))
{
return false;
}
m = n - 1;
while(!(m & 1))
{
k++, m >>= 1;
}
for(i = 0; i < 9; i++)
{
if(p[i] >= n)
{
return true;
}
u = quickmod(p[i], m, n);
if(u == 1)
{
continue;
}
for(j = 0; j < k; j++)
{
buf = multi_mod(u, u, n);
if(buf == 1 && u != 1 && u!= n - 1)
{
return false;
}
u = buf;
}
//如果p[i]^(n - 1)%n! = 1那么n为合数
if(u - 1)
{
return false;
}
}
return true;
}
// see http://www.cs.colorado.edu/~srirams/classes/doku.php/pollard_rho_tutorial
// and https://en.wikipedia.org/wiki/Pollard's_rho_algorithm
// Pollard's Rho algorithm for factoring numbers
//寻找n的一个因子,该因子并不一定是最小的,所以下面要二分查找最小的那个因子
ULL pollard(ULL n)
{
ULL i = 1;
ULL x = rand() % (n - 1) + 1;
ULL y = x;
ULL k = 2;
ULL d;
do
{
i++;
d = gcd(n + y - x, n);
if (d > 1 && d < n)
return d;
if (i == k)
{
y = x, k *= 2;
}
x = (multi_mod(x, x, n) + n - gcc) % n;
} while (y != x);
return n;
}
ULL MIN;
ULL pollard_min(ULL n)
{
ULL p, a, b = MAX;
if(n == 1)
{
return MAX;
}
if(miller_rabin(n))
{
return n;
}
p = pollard(n);
a = pollard_min(p);//二分查找
ULL y = n / p;
b = pollard_min(y);
return a < b? a : b;
}
int main(void)
{
ULL T;
ULL n;
scanf("%lld", &T);
while(T--)
{
scanf("%lld", &n);
MIN = MAX;
if(miller_rabin(n))
{
puts("Prime");
}
else printf("%lld\n", pollard_min(n));
}
return 0;
}