给你一个数n(n <= 2^54),判断n是不是素数,如果是输出Prime,否则输出n最小的素因子
参考:先用miller_rubin素数测试判断是否为素数,是则用Pollard rho因数分解得到最小素因子
以下代码是网上找的,前面的稳定在1S+,后面的1/3概率TLE,但是run time 稳定在500S
稳定1S+代码:
#include <cstdio> #include <cstdlib> #include <ctime> typedef __int64 LL; int T; LL n, s; LL factor[110000]; LL mods(LL x, LL y, LL n){ x %= n; y %= n; LL tmp = 0; while(y){ if(y & 1) tmp = (tmp + x) % n; x = (x << 1) % n; y >>= 1; } return tmp; } LL pow(LL x, LL y, LL n) { x %= n; LL tmp = 1; while(y){ if(y&1) tmp = mods(tmp, x, n); x = mods(x, x, n); y >>= 1; } return tmp; } int judge(LL tmp, LL n, LL m, LL t){//n - 1 == m * 2^ t LL tp = m; LL v = pow(tmp , m, n); LL last = v; for(LL i = 1; i <= t; i++){ v = mods(v, v, n); if(v == 1){ if(last != 1 && last != n-1) return 0; } last = v; tp <<= 1; } if(v == 1)return 1; return 0; } int miller_rubin(LL x, int k){ LL cnt = 0; LL m = x - 1; while(!(m & 1)) cnt++, m >>= 1; while(k--){ LL tmp = rand()%(x-1) + 1; if(!judge(tmp, x, m, cnt)){ return 0; } } return 1; } LL gcd(LL a, LL b){ return b == 0?a: gcd(b, a%b); } LL f(LL x, LL n, LL c){ return (mods(x, x, n) + c) % n; } LL poll(LL n, LL c){ if(!(n & 1))return 2; LL x = rand() % n; LL y = x; LL i = 1; LL k = 2; while(1){ i++; x = f(x, n, c); LL d = gcd(y - x + n, n); if(d != 1 && d != n) return d; if(y == x)return n; if(i == k){ y = x; k += k; } } } void find(LL n){ if(miller_rubin(n,5)){ factor[s++] = n; return; } LL p = n; while(p >= n) p = poll(p, (LL)(rand()%(n-1)+1)); find(p); find(n/p); } int main(){ srand(time(NULL)); scanf("%d",&T); while(T--){ scanf("%I64d",&n); if(n == 1)break; s = 0; find(n); if(s == 1){ printf("Prime\n"); continue; } LL tp = 10000000000LL; for(int i = 0; i < s; i++){ if(tp > factor[i]) tp = factor[i]; } printf("%I64d\n",tp); } return 0; }
大几率TLE,但是ac time 500ms+
//此代码提交有1/3几率TLE,但是AC时间稳定在500S- #include<iostream> #include<ctime> #include<cstdlib> #include<cmath> #include<algorithm> #define MAX (pow(2.0, 60)) //标记最大值 #define C 240 #define TIME 12 //Miller测试次数 using namespace std; __int64 MIN; __int64 gcd(__int64 a, __int64 b) //计算a和b的最大公约数 { if (b == 0) return a; return gcd(b, a % b); } __int64 mod_mult(__int64 a, __int64 b, __int64 n) //计算(a*b) mod n { __int64 s = 0; a = a % n; while (b) { if (b & 1) { s += a; if (s >= n) s -= n; } a = a << 1; if (a >= n) a -= n; b = b >> 1; } return s; } __int64 mod_exp(__int64 a, __int64 b, __int64 n) //计算(a^b) mod n { __int64 d = 1; a = a % n; while (b >= 1) { if (b & 1) d = mod_mult(d, a, n); a = mod_mult(a, a, n); b = b >> 1; } return d; } bool Wintess(__int64 a, __int64 n) //以a为基对n进行Miller测试并实现二次探测 { __int64 m, x, y; int i, j = 0; m = n - 1; while (m % 2 == 0) //计算(n-1)=m*(2^j)中的j和m,j=0时m=n-1,不断的除以2直至n为奇数 { m = m >> 1; j++; } x = mod_exp(a, m, n); for (i = 1; i <= j; i++) { y = mod_exp(x, 2, n); if ((y == 1) && (x != 1) && (x != n - 1)) //二次探测 return true; //返回true时,n是合数 x = y; } if (y != 1) return true; return false; } bool miller_rabin(int times, __int64 n) //对n进行s次的Miller测试 { __int64 a; int i; if (n == 1) return false; if (n == 2) return true; if (n % 2 == 0) return false; srand(time(NULL)); for (i = 1; i <= times; i++) { a = rand() % (n - 1) + 1; if (Wintess(a, n)) return false; } return true; } __int64 Pollard(__int64 n, int c) //对n进行因字分解,找出n的一个因子,注意该因子不一定是最小的 { __int64 i, k, x, y, d; srand(time(NULL)); i = 1; k = 2; x = rand() % n; y = x; while (true) { i++; x = (mod_mult(x, x, n) + c) % n; d = gcd(y - x, n); if (d > 1 && d < n) return d; if (y == x) //该数已经出现过,直接返回即可 return n; if (i == k) { y = x; k = k << 1; } } } void get_small(__int64 n, int c) //找出最小的素数因子 { __int64 m; if (n == 1) return; if (miller_rabin(TIME, n)) //判断是否为素数 { if (n < MIN) MIN = n; return; } m = n; while (m == n) //找出n的一个因子 m = Pollard(n, c--); get_small(m, c); //二分查找 get_small(n / m, c); } int main() { int total; __int64 n; scanf("%d", &total); while (total--) { scanf("%I64d", &n); MIN = MAX; if (miller_rabin(TIME, n)) printf("Prime\n"); else { get_small(n, C); printf("%I64d\n", MIN); } } return 0; }