2013-09-23 09:08:55Morris

[UVA][大整數因數分解] 11476 - Factorizing Larget Integers

 
Problem F
Factorizing Large Integers
Time Limit : 15 seconds

 


Given an integer N(≤10^16) find its prime factoring.

 
  Input    
  The first line of the input contains T(≤800) , the number of test cases. Then the next T lines contains an integer N (1 < N ≤10^16).  
     
  Output  
  For every test case output its prime factoring representation. See the sample output for the output format.  
     
  Sample Input Sample Output    
  3
60
36
10007
60 = 2^2 * 3 * 5
36 = 2^2 * 3^2
10007 = 10007
   
 

Problem Setter: Tasnim Imran Sunny
Special Thanks: Mir Wasi Ahmed
Next Generation Contest 5

     


參照 http://www.csie.ntnu.edu.tw/~u91029/Prime.html

需要兩個數學的演算法!

雖然還是逼近 TLE 的邊緣,不過 AC 就算了。


Miller-Rabin Algorithm & Pollard's ρ Algorithm
前者判斷是否為質數(根據概率在高效時間內回答)
後者根據亂數產生器,概率產生一部分的因數。

處理中最討厭的就是 x*y%mod。

因為 x, y, mod 都是 64 bits,很容易相乘就會 overflow。

很多人誤以為 (x%mod)*(y%mod)%mod 就可以解決 overflw,這是錯誤的想法。

真正作法請參照 modmultiply,模擬一般計算 binary 乘法的方式去計算。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
using namespace std;
#define LL long long
//http://www.csie.ntnu.edu.tw/~u91029/Prime.html
int p[5500], pt = 0;
void sieve() {
    int mark[46340] = {};
    int i, j;
    for(i = 2; i < 46340; i++) {
        if(mark[i] == 0) {
            p[pt++] = i;
            for(j = i+i; j < 46340; j += i)
                mark[j] = 1;
        }
    }
}
LL modmultiply(LL a,LL b,LL c) {
    LL x = 0,y = a%c;
    while(b > 0) {
        if(b%2 == 1) {
            x = (x+y)%c;
        }
        y = (y*2)%c;
        b /= 2;
    }
    return x%c;
}
LL modpow(LL x, LL y, LL mod) {
    LL ret = 1;// ret = x^y%mod;
    while(y) {
        if(y&1)
            //ret = (ret*x)%mod;
            ret = modmultiply(ret, x, mod);
        //x = (x*x)%mod;
        x = modmultiply(x, x, mod);
        y >>= 1;
    }
    return ret;
}
int isprime(LL n) {
    if(n == 2 || n == 3)
        return 1;
    if(n < 2 || (n&1) == 0)    
        return 0;
    int i, a;
    for(i = 0; i < 5; i++) {
        a = rand()%(n-4)+2;
        if(modpow(a, n-1, n) != 1)
            return 0;
    }
    return 1;
}
LL gcd(LL x, LL y)  {
    if(!x)    return y;
    if(!y)    return x;
    if(x < 0)    x = -x;
    if(y < 0)    y = -y;
    LL t;
    while(x%y)
        t = x, x = y, y = t%y;
    return y;
}
vector<LL> ret;
LL pollard_rho(LL n, LL c) {
    long long x = 2, y = 2;
    do {
        //x = (x*x+c)%n;
        x = (modmultiply(x, x, n)+c)%n;
        //y = (y*y+c)%n, y = (y*y+c)%n;
        y = (modmultiply(y, y, n)+c)%n;
        y = (modmultiply(y, y, n)+c)%n;
        LL d = gcd(x-y, n);
        if(d > 1)    return d;
    } while(true);
    return n;
}
void small_factorize(LL n) {
    int i;
    for(i = 0; i < pt && p[i]*p[i] <= n; i++) {
        if(n%p[i] == 0) {
            while(n%p[i] == 0)
                ret.push_back(p[i]), n /= p[i];
        }
    }
    if(n != 1)
        ret.push_back(n);
}
void factorize(LL n) {
    if(n == 1)    return;
    if(isprime(n)) {
        ret.push_back(n);
        return;
    }
    if(n < 1000000000) {
        small_factorize(n);
        return;
    }
    int c;
    LL d = n;
    for(c = 2; d == n; c++) {
        d = pollard_rho(n, c);
        //printf("%lld %lld\n", n, d);
    }
    factorize(d);
    factorize(n/d);
}
int main() {
    sieve();
    int i, j, k;
    LL n;
    int testcase;
    scanf("%d", &testcase);
    while(testcase--) {
        scanf("%lld", &n);
        ret.clear();
        factorize(n);
        sort(ret.begin(), ret.end());
        printf("%lld = ", n);
        long long x = ret[0], y = 1;
        int flag = 0;
        for(i = 1; i < ret.size(); i++) {
            if(ret[i] != x) {
                if(flag)    printf(" * ");
                flag = 1;
                printf("%lld", x);
                if(y != 1)    printf("^%lld", y);
                x = ret[i], y = 1;
            } else
                y++;
        }
        if(flag)    printf(" * ");
        flag = 1;
        printf("%lld", x);
        if(y != 1)    printf("^%lld", y);
        puts("");
    }
    return 0;
}
//8223372036854775841
//853362801814278496 x 7403927029032157185 = 6318235913923348540157928473237393760