zoukankan      html  css  js  c++  java
  • 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
    ");
            else printf("%lld
    ",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
    ");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
    ");
        else if(top==1){
            int cnt=0;
            while(n%st[top]==0)n/=st[top],cnt++;
            if(cnt==3)printf("%lld %lld %lld
    ",st[top],st[top]*st[top],st[top]*st[top]*st[top]);
            else printf("is not a D_num
    ");
        }else if(top==2){
            if(n==st[1]*st[2])printf("%lld %lld %lld
    ",st[1],st[2],st[1]*st[2]);
            else printf("is not a D_num
    ");
        }return;
    }
    
    int main(){
        while(scanf("%lld",&n)==1){
            if(n==1){printf("is not a D_num
    ");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
    ");
    		else printf("%lld
    ",mn);
    	}return 0;
    }
    

      

  • 相关阅读:
    1014 Waiting in Line (30)(30 point(s))
    1013 Battle Over Cities (25)(25 point(s))
    1012 The Best Rank (25)(25 point(s))
    1011 World Cup Betting (20)(20 point(s))
    1010 Radix (25)(25 point(s))
    1009 Product of Polynomials (25)(25 point(s))
    1008 Elevator (20)(20 point(s))
    1007 Maximum Subsequence Sum (25)(25 point(s))
    1006 Sign In and Sign Out (25)(25 point(s))
    1005 Spell It Right (20)(20 point(s))
  • 原文地址:https://www.cnblogs.com/joyouth/p/5645719.html
Copyright © 2011-2022 走看看