题目大意
给你一个非常大的整数,判断它是不是素数,如果不是则输出它的最小的因子
题解
看了一整天《初等数论及其应用》相关部分,终于把Miller–Rabin和Pollard's rho这两个算法看懂了O(∩_∩)O~~
Miller–Rabin主要用到了费马小定理,即:设p是一个素数,a是一个正整数且p不整除a,则ap-1≡1(mod p).若x=b(n-1)/2,x2=bn-1≡1(mod n),如果n是一个素数,则x≡1(mod n)或者x≡-1(mod n).因此,一旦我们有bn-1≡1(mod n),则可以检验b(n-1)/2≡±1(mod n)是否成立.若该同余式不成立,则可知n合数.因此我们可以令n-1=2tu,(t>=1且 u是奇数),bn-1≡(bu)^2t(mod n),通过先计算bu,然后对结果连续平方t次来计算bn-1(mod n),如果通过这种这种测试,则称n通过了以b为基数的米勒检验,我们可以多选取几个b,如果都通过了检测,则n有很大的机率是素数~~~
Pollard's rho 主要是基于Floyd's cycle-finding algorithm,算导上图非常形象~~讲得也挺好~~~我就不造轮子了。。。。我选取的函数式f(x)=x^2+1,每次都跑了1000多ms%>_<%。。。
#include<stdio.h> #include<stdlib.h> #include<time.h> typedef unsigned long long LL; LL min(LL a,LL b) { return a<b?a:b; } LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } LL mult_mod(LL a,LL b,LL mod) { LL ans=0; while(b) { if(b&1) ans=(ans+a)%mod; a=(a<<1)%mod; b>>=1; } return ans; } LL pow_mod(LL a,LL b,LL mod) { LL d=1; a%=mod; while(b) { if(b&1) d=mult_mod(d,a,mod); a=mult_mod(a,a,mod); b>>=1; } return d%mod; } bool witness(LL a,LL n) { LL u=n-1,t=0; while((u&1)==0) { u>>=1; t++; } LL x,x0=pow_mod(a,u,n); for(LL i=1; i<=t; i++) { x=mult_mod(x0,x0,n); if(x==1&&x0!=1&&x0!=(n-1)) return true; x0=x; } if(x!=1) return true; return false; } bool miller_rabin(LL n) { if(n==2) return true; if(n<2||!(n&1)) return false; for(int j=1; j<=8; j++) { LL a=rand()%(n-1)+1; if(witness(a,n)) return false; } return true; } LL pollard_rho(LL n) { LL i=1,x=2,y=2,k=2,d; while(true) { i++; x=(mult_mod(x,x,n)+1)%n; d=gcd(y-x,n); if(d!=1&&d!=n) return d; if(x==y) return n; if(i==k) { y=x; k<<=1; } } } LL find_minfac(LL n) { if(miller_rabin(n)||n<=1) return n; LL p=pollard_rho(n); LL q=min(find_minfac(p),find_minfac(n/p)); return q; } int main() { int T; LL n; scanf("%d",&T); srand(time(NULL)); while(T--) { scanf("%I64u",&n); if(n>2&&n%2==0) printf("2 "); else if(n==2||miller_rabin(n)) printf("Prime "); else printf("%I64u ",find_minfac(n)); } return 0; }