其他数论模板

miller-rabin素性判断+Pollard-rho算法分解质因数

下面这个代码不仅能判断素数还能给出质因数分解的结果(每一个质因子次数也能求出来),直接套用即可

#include <iostream> 
#include <cstdio> 
#include <algorithm>  
#include <cmath>  
#include <cstring>  
#include <map>  
#define LL long long
using namespace std;
 
const int times=20;
int number=0;
LL factor[100];
int tol;
map<LL,int> m;
                                                                
/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
LL Random(LL n)			//生成[ 0 , n ]的随机数
{
	return ((double)rand() / RAND_MAX*n + 0.5);
}
 
LL q_mul(LL a, LL b, LL mod) //快速计算 (a*b) % mod
{
	LL ans=0;
	while (b) {
		if (b&1) {
			b--;
			ans=(ans+a)%mod;
		}
		b/=2;
		a=(a+a)%mod;
	}
	return ans;
}
 
LL q_pow(LL a,LL b,LL mod) //快速计算 (a^b) % mod
{
	LL ans=1;
	while (b) {
		if (b&1)  ans = q_mul(ans, a, mod);
		b/=2;
		a=q_mul(a, a, mod);
	}
	return ans;
}

LL gcd(LL a,LL b)
{
    if (a==0) return 1;
    if (a<0) return gcd(-a,b);
    while (b)
    {
        LL t=a%b;
        a=b;
        b=t;
    }
    return a;
}   //  允许负数 

/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
bool witness(LL a, LL n)   //miller_rabin算法的精华 用检验算子a来检验n是不是素数
{
	LL tem=n-1;
	int j=0;
	while (tem%2 == 0) {
		tem/=2;
		j++;
	}
 
	LL x = q_pow(a,tem,n); 
	if (x==1 || x==n-1) return 1;
	while (j--) {
		x = q_mul(x, x, n);
		if (x==n-1) return 1;
	}
	return 0;
}
 
bool Miller_Rabin(LL n) 
{
	if (n==2) return 1;
	if (n<2 || n%2==0)  return 0;			
 
	for (int i=1; i<=times; i++) {
		LL a = Random(n-2)+1; 
		if (!witness(a,n))  return 0;
	}
	return 1;
}

/*----------------------------------------------------------*/
/*----------------------------------------------------------*/
LL Pollard_rho(LL x,LL c)
{
    LL i=1,k=2;
    LL x0=rand()%x;
    LL y=x0;
    while (1) {
        i++;
        x0 = (q_mul(x0,x0,x)+c)%x;
        LL d=gcd(y-x0,x);
        if (d!=1 && d!=x) return d;
        if (y==x0) return x;
        if (i==k) { y=x0; k+=k; }
    }
}

void findfac(LL n)
{
    if (Miller_Rabin(n)) {
        factor[++tol]=n;
        return;
    }
    LL p=n;
    while (p>=n) p = Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}
 

int main()
{
	LL tar;
	while (cin >> tar)
	{
		if (Miller_Rabin(tar))	cout << "Yes, Prime!" << endl;
		else cout << "No, not prime.." << endl;
		
		tol=0;
		findfac(tar);
		for (int i=1; i<=tol; i++ ) cout<<factor[i]<<' '; cout<<endl;
	}
	return 0;
}

 

原根

下面这个代码能求出所有原根,直接套用即可

#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1000001;
int m[N],phi[N],p[N],tot,prime[N];
//m[i]是i的最小素因数

void initPhi(){
    phi[1]=1;
    int k;
    for(int i=2;i<N;i++){
        if(!m[i]){
            p[tot++]=m[i]=i;
            prime[i]=1;
            phi[i]=i-1;
        }
        for(int j=0;j<tot&&(k=p[j]*i)<N;j++){
            m[k]=p[j];
            if(m[i]==p[j]){
                phi[k]=phi[i]*p[j];break;   
            }
            else phi[k]=phi[i]*(p[j]-1);
        }
    }
}

int root[N]={0};
void initRoot(){
    root[2]=root[4]=1;
    //从第二个质数3开始
    for(int i=1;i<tot;i++){
        for(LL j=p[i];j<N;j*=p[i]){
            root[j]=1;
        }
        for(LL j=2*p[i];j<N;j*=p[i]){
            root[j]=2;
        }
    }
}
 
vector<int> getfac(int n){
    vector<int>fac;
    LL tmp=n;
    for(int i=0;tmp>1&&i<tot;i++){
        if(tmp%p[i]==0){
            fac.push_back(p[i]);
            while(tmp%p[i]==0)tmp/=p[i];
        }
    }
    if(tmp>1)fac.push_back(tmp);
    return fac;
}

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int ans[N],ia;
//已知n的一个原根x求n的所有phi(phi(n))个原根
void getRoot(int n,int x){
    ia=0;
    ans[ia++]=x;
    int y=x;
    for(int i=2;i<phi[n];i++){
        y=(y*x)%n;
        if(gcd(i,phi[n])==1)ans[ia++]=y;
    }
    sort(ans,ans+ia);
}

LL pow_mod(LL a,LL b,LL p){
    LL ret=1;
    while(b){
        if(b&1)ret=(ret*a)%p;
        a=(a*a)%p;
        b>>=1;
    }
    return ret;
}

//求n的一个原根
int oneRoot(int n){
    vector<int> fac=getfac(phi[n]);
    for(int i=1;i<n;i++){
        int flag=1;
        if(pow_mod(i,phi[n],n)!=1)flag=0;
        else
        for(int j=0;j<fac.size();j++){
            if(pow_mod(i,phi[n]/fac[j],n)==1){
                flag=0;
                break;
            }
        }
        if(flag)return i;
    }
    return 0;
}

void getRoot(int n){
    if(n==1||n==2||n==3)printf("%d\n",n-1);
    else if(root[n]){
        getRoot(n,oneRoot(n));
        for(int i=0;i<ia;i++){
            if(i)printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    else printf("-1\n");
}

int main(){
    initPhi();
    initRoot();
    int n;
    while(~scanf("%d",&n)){
        getRoot(n);
    }
    return 0;
} 

离散对数

下面这个代码解决了A^x=B(mod C)的x,直接套用即可

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<cmath>  
#define LL __int64  
#define N 1000000  
using namespace std;  
struct Node{  
    int idx;  
    int val;  
}baby[N];  

bool cmp(Node n1,Node n2){  
    return n1.val!=n2.val?n1.val<n2.val:n1.idx<n2.idx;  
}  

int gcd(int a,int b){  
    return b==0?a:gcd(b,a%b);  
}
  
int extend_gcd(int a,int b,int &x,int &y){  
    if(b==0){  
        x=1;  
        y=0;  
        return a;  
    }  
    int gcd=extend_gcd(b,a%b,x,y);  
    int t=x;  
    x=y;  
    y=t-a/b*y;  
    return gcd;  
}
  
int inval(int a,int b,int n){  
    int e,x,y;  
    extend_gcd(a,n,x,y);  
    e=((LL)x*b)%n;  
    return e<0?e+n:e;  
}
  
int PowMod(int a,int b,int MOD){  
    LL ret=1%MOD,t=a%MOD;  
    while(b){  
        if(b&1)  
            ret=((LL)ret*t)%MOD;  
        t=((LL)t*t)%MOD;  
        b>>=1;  
    }  
    return (int)ret;  
}
  
int BinSearch(int num,int m){  
    int low=0,high=m-1,mid;  
    while(low<=high){  
        mid=(low+high)>>1;  
        if(baby[mid].val==num)  
            return baby[mid].idx;  
        if(baby[mid].val<num)  
            low=mid+1;  
        else  
            high=mid-1;  
    }  
    return -1;  
}
  
int BabyStep(int A,int B,int C){  
    LL tmp,D=1%C;  
    int temp;  
    for(int i=0,tmp=1%C;i<100;i++,tmp=((LL)tmp*A)%C)  
        if(tmp==B)  
            return i;  
    int d=0;  
    while((temp=gcd(A,C))!=1){  
        if(B%temp) return -1;  
        d++;  
        C/=temp;  
        B/=temp;  
        D=((A/temp)*D)%C;  
    }  
    int m=(int)ceil(sqrt((double)C));  
    for(int i=0,tmp=1%C;i<=m;i++,tmp=((LL)tmp*A)%C){  
        baby[i].idx=i;  
        baby[i].val=tmp;  
    }  
    sort(baby,baby+m+1,cmp);  
    int cnt=1;  
    for(int i=1;i<=m;i++)  
        if(baby[i].val!=baby[cnt-1].val)  
            baby[cnt++]=baby[i];  
    int am=PowMod(A,m,C);  
    for(int i=0;i<=m;i++,D=((LL)(D*am))%C){  
        int tmp=inval(D,B,C);  
        if(tmp>=0){  
            int pos=BinSearch(tmp,cnt);  
            if(pos!=-1)  
                return i*m+pos+d;  
        }  
    }  
    return -1;  
}
  
int main(){  
    int A,B,C;  
    while(scanf("%d%d%d",&A,&C,&B)!=EOF){  
        if(B>=C){  
            puts("Orz,I can’t find D!");  
            continue;  
        }  
        int ans=BabyStep(A,B,C);  
        if(ans==-1)  
            puts("Orz,I can’t find D!");  
        else  
            printf("%d\n",ans);  
    }  
    return 0;  
}  

二次剩余

占坑,有空补

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值