素数判定的模板题,运用米勒-罗宾素数判定,然后用Pollard_Rho法求出质因数。使用相应的模板即可,不过注意存储质因子的数组需要使用vector,并且使用long long类型存储,不然存储不下,而且输出最下的质因子时,需要写个迭代器进行查询。
完整代码如下:
#include<iostream> #include<algorithm> #include<vector> using namespace std; typedef long long LL; vector <LL> fac; LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); } LL mul_mod(LL a, LL x, LL n) ///计算a*x%n,其中t用于存储结果,当t>=n的时候,t对n的模减去n即可(不会出现t>=2*n的情况,因为a也对n取了模) { LL t = 0; while(x) { if(x & 1) { t += a; if(t >= n) t -= n; } a <<= 1; if(a >= n) a -= n; x >>= 1; } return t; } LL pow2_mod(LL a, LL x, LL n)/// //乘方快速幂 { LL t = 1; a %= n; while(x) { if(x & 1) t = mul_mod(t, a, n); a = mul_mod(a, a, n); x >>= 1; } return t; } ///不断选取不超过n-1的基b(s次),计算是否每次都有b^(n-1) ≡ 1(mod n),若每次都成立则n是素数,否则为合数。 bool test(LL n, LL a, LL d)///n 为测试数,a为素数表中的数,d为正奇数,这里运用位运算,将n-1不断通过快速幂,同时将n-1向左位移,进行抽出指数中2的操作,从而不断进行素数检测 { if(n == 2) return true;///为2肯定是素数 if(n == a) return true;///如果n等于素数表里面的数则肯定是素数 if((n&1) == 0) return false;///如果是偶数,则肯定不是素数 while(!(d&1)) d >>=1;///选取奇数 LL t = pow2_mod(a, d, n);///进行快速幂运算 while((d != n-1) && (t != 1) && (t != n-1))///由二次探测定理可知,只有当t等于1或者n-1时,n才为素数 { /// t = (LL)t*t%n; t = mul_mod(t, t, n); d = d<<1; } return (t == n-1 || (d&1) == 1); } bool isPrime(LL n) { ///有些题目把1看作质数,但是负数不会是质数 if(n < 2) return false; LL a[] = {2, 3, 61}; for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false; return true; } LL Pollard_Rho(LL n, LL c) { LL x, y, d; LL i = 1, k = 2; x = y = rand() % n; do { i++; d = gcd(n + y - x, n); if(d > 1 && d < n) return d; if(i == k) { y = x; k <<= 1; } x = (mul_mod(x, x, n) + n - c) % n; } while(y != x); return n; } void rhoAll(LL n) { if(n <= 1) return; if(isPrime(n)) { fac.push_back(n); return; } LL t = n; while(t >= n) t = Pollard_Rho(n, rand() % (n-1) + 1); rhoAll(t); rhoAll(n/t); return; } int main() { LL n; int t; cin>>t; while(t--) { while(cin>>n) { if(isPrime(n)) cout<<"Prime"<<endl; else { fac.clear(); rhoAll(n); LL mins=100000000000; for(vector<LL> ::iterator it=fac.begin();it!=fac.end();++it) mins=min(mins,*it); cout<<mins<<endl; } } } return 0; }
其中米勒-罗宾判断法模板如下:
typedef long long LL; LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); } LL mul_mod(LL a, LL x, LL n) ///计算a*x%n,其中t用于存储结果,当t>=n的时候,t对n的模减去n即可(不会出现t>=2*n的情况,因为a也对n取了模) { LL t = 0; while(x) { if(x & 1) { t += a; if(t >= n) t -= n; } a <<= 1; if(a >= n) a -= n; x >>= 1; } return t; } LL pow2_mod(LL a, LL x, LL n)/// //乘方快速幂 { LL t = 1; a %= n; while(x) { if(x & 1) t = mul_mod(t, a, n); a = mul_mod(a, a, n); x >>= 1; } return t; } ///不断选取不超过n-1的基b(s次),计算是否每次都有b^(n-1) ≡ 1(mod n),若每次都成立则n是素数,否则为合数。 bool test(LL n, LL a, LL d)///n 为测试数,a为素数表中的数,d为正奇数,这里运用位运算,将n-1不断通过快速幂,同时将n-1向左位移,进行抽出指数中2的操作,从而不断进行素数检测 { if(n == 2) return true;///为2肯定是素数 if(n == a) return true;///如果n等于素数表里面的数则肯定是素数 if((n&1) == 0) return false;///如果是偶数,则肯定不是素数 while(!(d&1)) d >>=1;///选取奇数 LL t = pow2_mod(a, d, n);///进行快速幂运算 while((d != n-1) && (t != 1) && (t != n-1))///由二次探测定理可知,只有当t等于1或者n-1时,n才为素数 { /// t = (LL)t*t%n; t = mul_mod(t, t, n); d = d<<1; } return (t == n-1 || (d&1) == 1); } bool isPrime(LL n) { ///有些题目把1看作质数,但是负数不会是质数 if(n < 2) return false; LL a[] = {2, 3, 61}; for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false; return true; }
Pollard_Rho法求大数的质因子代码模板如下:
vector <LL> fac; LL Pollard_Rho(LL n, LL c) { LL x, y, d; LL i = 1, k = 2; x = y = rand() % n; do { i++; d = gcd(n + y - x, n); if(d > 1 && d < n) return d; if(i == k) { y = x; k <<= 1; } x = (mul_mod(x, x, n) + n - c) % n; } while(y != x); return n; } void rhoAll(LL n) { if(n <= 1) return; if(isPrime(n)) { fac.push_back(n); return; } LL t = n; while(t >= n) t = Pollard_Rho(n, rand() % (n-1) + 1); rhoAll(t); rhoAll(n/t); return; }
迭代器书写格式如下:
vector<LL> ::iterator it=fac.begin()///用于遍历vector数组
浙公网安备 33010602011771号