之前学的都是假的
Miller_Rabin:Miller-Rabin与二次探测
大质数分解:
找到所有质因子,再logn搞出质因子的次数
方法:不断找到一个约数d,递归d,n/d进行分解,直到n是质数
快速幂快速乘:
ll qk(ll a,ll b,ll m){ ll d=((long double)a/m*b); ll r=a*b-d*m; return ((ull)r+m)%m; } ll qm(ll x,ll y,ll mod){ ll ret=1; while(y){ if(y&1) ret=qk(ret,x,mod); x=qk(x,x,mod); y>>=1; } return ret; }
注意快速乘:((ull)r+m)%m由于r可能<0或者>m,这一步是必须的
Miller-Rabin:
const int pri[6]={2,3,5,7,11,61}; bool M_R(ll n){ if(n==1) return false; if(n==2||n==3||n==5||n==7||n==11||n==13||n==61) return true; if(n==46856248255981ll) return false; if(n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%13==0) return false; ll tmp=n-1,s=0; while(!(tmp&1)) tmp>>=1,++s; for(reg i=0;i<=5;++i){ ll p=pri[i]; ll lp=qm(p,tmp,n); if(lp==1||lp==n-1) continue; ll las; for(reg j=1;j<=s;++j){ las=lp; lp=qk(lp,lp,n); if(lp==1&&(las!=1&&las!=n-1)) return false; } if(lp!=1) return false; } return true; }
二进制gcd
ll gcd(ll a,ll b) { if(!a||!b) return a|b; #define ctz __builtin_ctzll int shift=ctz(a|b); b>>=shift; while(a) { a>>=ctz(a); if(a<b) swap(a,b); a-=b; } return b<<shift; #undef ctz }
就是高精gcd才用的更相减损术
Pollard-Rho
主体1
ll P_R(ll n,ll c){ ll x=0,y=0,d; int k=2,has=1; ll tmp=1; while(1){ ++has; x=(qk(x,x,n)+c)%n; tmp=qk(tmp,abs(y-x),n); if(x==y) return n; if(has==k){ y=x;k<<=1; d=gcd(tmp,n); tmp=1; if(d==n) break; if(d>1){ return d; } } } d=1; while(d==1){ x=(qk(x,x,n)+c)%n;d=gcd(abs(y-x),n); } return d; }
注意tmp,把所有的abs(y-x)乘在一起,gcd显然不变,并且减少了求gcd次数
最后如果d=n,特殊把环再跑一边
主体2
void find(ll n,ll cnt){ if(n==1||n<=ans) return; if(M_R(n)){ ans=max(ans,n);return; } ll p=P_R(n,cnt); while(n==p) p=P_R(n,--cnt); while(n%p==0) n/=p; find(p,cnt);find(n,cnt); }
如果要求质因子,开个vector,最后去重即可
模板:
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define ull unsigned long long #define LL ll using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{ int t; ll n,ans; ll qk(ll a,ll b,ll m){ ll d=((long double)a/m*b); ll r=a*b-d*m; return ((ull)r+m)%m; } ll qm(ll x,ll y,ll mod){ ll ret=1; while(y){ if(y&1) ret=qk(ret,x,mod); x=qk(x,x,mod); y>>=1; } return ret; } const int pri[6]={2,3,5,7,11,61}; bool M_R(ll n){ if(n==1) return false; if(n==2||n==3||n==5||n==7||n==11||n==13||n==61) return true; if(n==46856248255981ll) return false; if(n%2==0||n%3==0||n%5==0||n%7==0||n%11==0||n%13==0) return false; ll tmp=n-1,s=0; while(!(tmp&1)) tmp>>=1,++s; for(reg i=0;i<=5;++i){ ll p=pri[i]; ll lp=qm(p,tmp,n); if(lp==1||lp==n-1) continue; ll las; for(reg j=1;j<=s;++j){ las=lp; lp=qk(lp,lp,n); if(lp==1&&(las!=1&&las!=n-1)) return false; } if(lp!=1) return false; } return true; } ll gcd(ll a,ll b) { if(!a||!b) return a|b; #define ctz __builtin_ctzll int shift=ctz(a|b); b>>=shift; while(a) { a>>=ctz(a); if(a<b) swap(a,b); a-=b; } return b<<shift; #undef ctz } ll P_R(ll n,ll c){ ll x=0,y=0,d; int k=2,has=1; ll tmp=1; while(1){ ++has; x=(qk(x,x,n)+c)%n; tmp=qk(tmp,abs(y-x),n); if(x==y) return n; if(has==k){ y=x;k<<=1; d=gcd(tmp,n); tmp=1; if(d==n) break; if(d>1){ return d; } } } d=1; while(d==1){ x=(qk(x,x,n)+c)%n;d=gcd(abs(y-x),n); } return d; } void find(ll n,ll cnt){ if(n==1||n<=ans) return; if(M_R(n)){ ans=max(ans,n);return; } ll p=P_R(n,cnt); while(n==p) p=P_R(n,--cnt); while(n%p==0) n/=p; find(p,cnt);find(n,cnt); } int main(){ int t; srand(19260817); rd(t); while(t--){ ll n;rd(n); ans=0;find(n,19260817); if(ans==n) puts("Prime"); else printf("%lld\n",ans); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/4/2 21:40:31 */