2013-09-23 09:08:55Morris
[UVA][大整數因數分解] 11476 - Factorizing Larget Integers
Problem F |
Factorizing Large Integers |
Time Limit :
15 seconds |
||||
|
||||||
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 |
參照 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