pollard_rho 学习总结 Miller_Rabbin 复习总结
Posted _Vertical
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pollard_rho 学习总结 Miller_Rabbin 复习总结相关的知识,希望对你有一定的参考价值。
吐槽一下名字,泼辣的肉。。OwO
我们知道分解出一个整数的所有质因子是O(sqrt(n)/ln(n))的
但是当n=10^18的时候就显得非常无力的
这个算法可以在大概O(n^(1/4))的时间复杂度的情况下把n分解成p*q
递归分解就可以得到质因子了,跑得非常快
做法是这样的,考虑利用生日悖论
设范围为[1,365]的正整数
设集合{x1,x2……,xk}当k大概到58时
那么这个集合中存在两个数相等的概率几乎为99%
那么相应的对于一个数n,我们随机一个集合,这个集合中任取两个数x,y,gcd(abs(x-y),n)不为1的概率也是很大的
但是集合中两两枚举判断是很麻烦的,所以我们可以考虑迭代求解
通常情况下利用f(x)=(x*x+c)%n来迭代生成伪随机数
之后做法有两种,一种是每次迭代并判断(x,f(x))是否是满足条件的(x,y)对
这个做法的缺点是因为f函数存在f环,所以很容易陷入死循环,所以需要写floyd判圈算法
如果存在环直接跳出重新随机x和c
第二种做法是固定一个y,之后利用函数迭代生成x并判断
然后定期随机一个y,gcd为n时跳出,然后反复多次随机x和c即可
第二种做法写起来比较简单,但是貌似没有第一种快
Miller_Rabbin算法是用来判断一个数是否是素数的
判断标准有两个:
1、随机基底a,若a^(p-1)%p!=1,则p一定不是素数,否则可能是
2、若x^2%p=1的解除了p-1和1外还有别的,则p一定不是素数,否则可能是
对于第二个条件的判断是把p-1表示成q*2^s的形式
然后再判断第一个条件做平方的时候顺便判断一下第二个
一次失败概率大概是(1/4)左右,随机若干次判断即可
QAQ 昨天只用第一种判断方式WA的我不省人事 QAQ
刷了一些模板题,发现边界各种醉
BZOJ 3667
裸模板题,注意质数判断要两个条件一起用
然后要写O(1)快速乘,不然会T
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; int T; LL n,mx; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL mul_mod(LL a,LL b,LL p){ a%=p;b%=p; LL t=(a*b-(LL)((double)a/p*b+0.5)*p); return t<0?t+p:t; } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=mul_mod(tmp,v,mod); v=mul_mod(v,v,mod);p>>=1; }return tmp; } bool Get_judge(LL v,LL mod,LL p,LL s){ v=pow_mod(v,p,mod); for(LL i=1,now=v;i<=s;++i){ v=mul_mod(v,v,mod); if(v==1&&now!=1&&now!=mod-1)return true; now=v; }return v!=1; } bool Get_check(LL n){ if(n==2||n==3)return true; if(n%2==0)return false; if(n%3==0)return false; LL p=n-1,s=0; while(!(p&1))p>>=1,s++; for(int i=0;i<10;++i)if(Get_judge(rand()%(n-2)+1,n,p,s))return false; return true; } LL Get_FJ(LL n,LL c){ LL k=2,x=rand()%n,y=x,p=1; for(LL i=1;p==1;++i){ x=(mul_mod(x,x,n)+c)%n; p=gcd(abs(x-y),n); if(i==k)y=x,k<<=1; }return p; } void Get_ans(LL n){ if(n==1)return; if(Get_check(n)){mx=max(mx,n);return;} LL tmp=n; while(tmp==n)tmp=Get_FJ(n,rand()%(n-2)+1); Get_ans(tmp);Get_ans(n/tmp); } int main(){ scanf("%d",&T); while(T--){ scanf("%lld",&n); mx=0;Get_ans(n); if(mx==n)printf("Prime\n"); else printf("%lld\n",mx); }return 0; }
BZOJ 4522 CQOI 密钥破解
直接按照题意模拟即可
先用泼辣的肉分解,然后ex_gcd,最后快速幂
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; LL e,N,c,p,q,r; LL d,x,y; LL mul_mod(LL a,LL b,LL mod){ LL s=0; while(b){ if(b&1)s=(s+a)%mod; a=(a<<1)%mod;b>>=1; }return s; } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=mul_mod(tmp,v,mod); v=mul_mod(v,v,mod);p>>=1; }return tmp; } LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y){ if(b==0){d=a;x=1;y=0;} else{ex_gcd(b,a%b,d,y,x);y-=(a/b)*x;} } LL Get_FJ(LL n,LL c){ LL k=2,x=rand()%n,y=x,p=1; for(LL i=1;p==1;++i){ x=(mul_mod(x,x,n)+c)%n; p=gcd(abs(x-y),n); if(i==k)y=x,k<<=1; }return p; } int main(){ scanf("%lld%lld%lld",&e,&N,&c); p=N; while(p==N)p=Get_FJ(N,rand()%(N-2)+1); q=N/p;r=(p-1)*(q-1); ex_gcd(e,r,d,x,y);d=r/d; x=(x%d+d)%d; y=pow_mod(c,x,N); printf("%lld %lld",x,y); return 0; }
hdu 4344
分解出所有质因数
直接上模板,注意看题目要求就可以了
(N>L)
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cstdlib> using namespace std; typedef unsigned long long LL; int T,top=0; LL st[1010]; LL n,ans; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL mul_mod(LL a,LL b,LL mod){ LL s=0; while(b){ if(b&1)s=(s+a)%mod; a=(a<<1)%mod;b>>=1; }return s; } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=mul_mod(tmp,v,mod); v=mul_mod(v,v,mod);p>>=1; }return tmp; } bool Get_judge(LL v,LL mod,LL p,LL s){ v=pow_mod(v,p,mod); for(LL i=1,now=v;i<=s;++i){ v=mul_mod(v,v,mod); if(v==1&&now!=mod-1&&now!=1)return true; now=v; }return v!=1; } bool Get_check(LL n){ if(n==2||n==3)return true; if(n%2==0||n%3==0)return false; LL p=n-1,s=0; while(!(p&1))p>>=1,s++; for(int i=0;i<10;++i)if(Get_judge(rand()%(n-2)+1,n,p,s))return false; return true; } LL Get_FJ(LL n,LL c){ LL k=2,x=rand()%n,y=x,p=1; for(LL i=1;p==1;++i){ x=(mul_mod(x,x,n)+c)%n; p=gcd(x<=y?y-x:x-y,n); if(i==k)y=x,k<<=1; }return p; } void Get_ans(LL n){ if(n==1)return; if(Get_check(n)){st[++top]=n;return;} LL tmp=n; while(tmp==n)tmp=Get_FJ(n,rand()%(n-2)+1); Get_ans(tmp);Get_ans(n/tmp); } int main(){ srand(110); scanf("%d",&T); while(T--){ cin>>n;top=0; if(n==1){printf("1 1\n");continue;} Get_ans(n);ans=0; sort(st+1,st+top+1); top=unique(st+1,st+top+1)-st-1; printf("%d ",top); for(int i=1;i<=top;++i){ LL now=1; while(n%st[i]==0)n/=st[i],now*=st[i]; ans+=now; } if(top==1)ans/=st[top]; cout<<ans<<endl; }return 0; }
hdu 3864
分解之后分类讨论一下
注意n=p^3这种情况
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; int top=0; LL n; LL st[1010]; LL mul_mod(LL a,LL b,LL mod){ LL s=0; while(b){ if(b&1)s=(s+a)%mod; a=(a<<1)%mod;b>>=1; }return s; } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=mul_mod(tmp,v,mod); v=mul_mod(v,v,mod);p>>=1; }return tmp; } LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL Get_FJ(LL n,LL c){ LL k=2,x=rand()%n,y=x,p=1; for(LL i=1;p==1;++i){ x=(mul_mod(x,x,n)+c)%n; p=gcd(abs(x-y),n); if(i==k)y=x,k<<=1; }return p; } bool Get_judge(LL v,LL mod,LL p,LL s){ v=pow_mod(v,p,mod); for(LL i=1,now=v;i<=s;++i){ v=mul_mod(v,v,mod); if(v==1&&now!=mod-1&&now!=1)return true; now=v; } return v!=1; } bool Get_check(LL n){ if(n==2||n==3)return true; if(n%2==0||n%3==0)return false; LL p=n-1,s=0; while(!(p&1))p>>=1,s++; for(int i=0;i<10;++i)if(Get_judge(rand()%(n-1)+1,n,p,s))return false; return true; } void Get_ans(LL n){ if(n==1)return; if(Get_check(n)){st[++top]=n;return;} LL tmp=n; while(tmp==n)tmp=Get_FJ(n,rand()%(n-1)+1); Get_ans(tmp);Get_ans(n/tmp); } void Get_print(){ if(top>=3)printf("is not a D_num\n"); else if(top==1){ int cnt=0; while(n%st[top]==0)n/=st[top],cnt++; if(cnt==3)printf("%lld %lld %lld\n",st[top],st[top]*st[top],st[top]*st[top]*st[top]); else printf("is not a D_num\n"); }else if(top==2){ if(n==st[1]*st[2])printf("%lld %lld %lld\n",st[1],st[2],st[1]*st[2]); else printf("is not a D_num\n"); }return; } int main(){ while(scanf("%lld",&n)==1){ if(n==1){printf("is not a D_num\n");continue;} top=0;Get_ans(n); sort(st+1,st+top+1); top=unique(st+1,st+top+1)-st-1; Get_print(); }return 0; }
poj 1811
裸题,注意要交G++
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const LL oo=1LL<<60; int T; LL n,mn; LL mul_mod(LL a,LL b,LL mod){ LL s=0; while(b){ if(b&1)s=(s+a)%mod; a=(a<<1)%mod;b>>=1; }return s; } LL pow_mod(LL v,LL p,LL mod){ LL tmp=1; while(p){ if(p&1)tmp=mul_mod(tmp,v,mod); v=mul_mod(v,v,mod);p>>=1; }return tmp; } LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL Get_FJ(LL n,LL c){ LL k=2,x=rand()%n,y=x,p=1; for(LL i=1;p==1;++i){ x=(mul_mod(x,x,n)+c)%n; p=gcd(x<=y?y-x:x-y,n); if(i==k)y=x,k<<=1; }return p; } bool Get_judge(LL v,LL mod,LL p,LL s){ v=pow_mod(v,p,mod); for(LL i=1,now=v;i<=s;++i){ v=mul_mod(v,v,mod); if(v==1&&now!=1&&now!=mod-1)return true; now=v; }return v!=1; } bool Get_check(LL n){ if(n==2||n==3)return true; if(n%2==0||n%3==0)return false; LL p=n-1,s=0; while(!(p&1))p>>=1,s++; for(int i=0;i<20;++i)if(Get_judge(rand()%(n-1)+1,n,p,s))return false; return true; } void Get_ans(LL n){ if(n==1)return; if(Get_check(n)){mn=min(mn,n);return;} LL tmp=n; while(tmp==n)tmp=Get_FJ(n,rand()%(n-1)+1); Get_ans(tmp);Get_ans(n/tmp); } int main(){ scanf("%d",&T); while(T--){ scanf("%lld",&n); mn=oo;Get_ans(n); if(mn==n)printf("Prime\n"); else printf("%lld\n",mn); }return 0; }
以上是关于pollard_rho 学习总结 Miller_Rabbin 复习总结的主要内容,如果未能解决你的问题,请参考以下文章
POJ 2429 GCD & LCM Inverse(Pollard_Rho+dfs)
随机素数测试(Miller_Rabin算法)和求整数素因子(Pollard_rho算法)