其实刚开始知道这个算法时,我以为需要字符串操作什么的,毕竟是大数嘛,可这家伙只用了个long long,无语了....
long long int,能叫大数吗,连2^100次方都处理不了。
说是这样说,这个算法已经不错了,复杂度为O(n^1/4), 貌似目前学界没有找到特别好的算法,据说有什么艾-鲁法,威廉斯夫法,可以分解一个千位素数(需要一周时间)(上面两种算法百度不到QAQ),量子的那个shore法应该很快。
对于一个大整数n,我们取任意一个数xx使得xx是nn的质因数的几率很小,但如果取两个数x1x1以及x2
使得它们的差是n的因数的几率就提高了,如果取x1以及x2使得gcd(abs(x1-x2), n) > 1的概率就更高了,这就是Pollard-Rho算法的思想。(概率的增加是因为组合数增加了)
又因为是质因数分解,所以我们要用到Miller_Rabbin算法来判断是否为素数,而随机地取x1, x2,我们则是在[1~n]中随机取x1,x2由x[i] = (x[i-1]*x[i-1]%n+c)%n,推算出来。
一个普遍模板如下:
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 105;
ll x[maxn], ans;
queue aria;
ll min(ll a, ll b)
{
if(a < b) return a;
else return b;
}
ll multi(ll a, ll b, ll p) //快速乘?
{
ll ans = 0;
while(b){
if(b & 1LL) ans = (ans+a)%p;
a = (a+a)%p;
b >>= 1;
}
return ans;
}
ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
while(b){
if(b & 1LL) ans = multi(ans, a, p);
a = multi(a, a, p);
b >>= 1;
}
return ans;
}
bool MR(ll n)
{
if(n == 2) return true;
int s = 20, i, t = 0;
ll u = n-1;
while(!(u&1)){
t++;
u >>= 1;
}
while(s--){
ll a = rand()%(n-2)+2;
x[0] = qpow(a, u, n);
for(i = 1; i <= t; i++){
x[i] = multi(x[i-1], x[i-1], n);
if(x[i] == 1 && x[i-1] != 1 && x[i-1] != n-1) return false;
}
if(x[t] != 1) return false;
}
return true;
}
ll gcd(ll a, ll b)
{
if(b == 0) return a;
else return gcd(b, a%b);
}
ll Pollard_Rho(ll n, int c)
{
ll i = 1, k = 2, x = rand()%(n-1)+1, y = x;
while(1){
i++;
x = (multi(x, x, n)+c)%n;
ll p = gcd((y-x+n)%n, n);
if(p != 1 && p != n) return p;
if(y == x) return n;
if(i == k){
y = x;
k <<= 1;
}
}
}
void find(ll n, int c)
{
if(n == 1) return;
if(MR(n)){
aria.push(n);
return;
}
ll p = n, k = c;
while(p >= n){
p = Pollard_Rho(p, c--);
}
find(p, k);
find(n/p, k);
}
int main()
{
ll n;
while(~scanf("%lld", &n)){
find(n, 107);
cout << aria.front();
aria.pop();
while(!aria.empty()){
cout << "*" << aria.front();
aria.pop();
}
cout << endl;
}
return 0;
}
POJ 1811这是一道裸题,输出最小素数即可