质数

质数的判定

暴力判定

O(N)O(\sqrt N)

bool is_prime(ll n){
    if(n<2)
        return 0;
    ll k=sqrt(n);
    for(ll i=2;i<=k;i++)
        if(n%i==0)
            return 0;
    return 1;
}

随机化

O(klogn)O(k\log n)

根据费马小定理,若 pp 为质数,则 ap1=1(modp)a^{p-1}=1\pmod p,虽然反过来不一定成立,但使用多次随机的 aa 可以大概判定是否为质数,kk 可以自己设定一个大一点的数保证结果精确度。

但如果 nn 是一些伪素数(不是质数却拥有质数的一些特性的数)或判定一段连续的 nn,则会有较大的出错概率,所以这拼的是rp谨慎使用

需要快速幂

bool is_prime(int k,ll n){
	if(n<2)
		return 0;
	for(int i=1;i<=k;i++)
		if(qmi(rand(),n-1,n)^1)
			return 0;
	return 1;
}

Miller_Rabin 算法

需要龟速乘的快速版本及其优化的快速幂

变量

  • long long pri[14]\texttt{long long pri[14]}:可用底数数组,其中 pri0pri_0 为个数。

函数

  • bool Miller_Rabin(ll n)\texttt{bool Miller\_Rabin(ll n)}:判断 nn 是否是质数。

代码

//long long pri[14]={7,2,325,9375,28178,450775,9780504,1795265022ll};
long long pri[14]={12,2,3,5,7,11,13,17,19,23,29,31,37};
bool Miller_Rabin(ll n){
	if(n<3||n%2==0)return n==2;
	ll u=n-1,t=0;
	while(!(u&1))u/=2,t++;
	for(int i=1;i<=pri[0]&&pri[i]<n;i++){
		ll a=pri[i],v=qmi(a,u,n),s;
		if(v==1)continue;
		for(s=1;s<=t;s++){
			if(v==n-1)break;
			v=mul(v,v,n);
		}
		if(s>t)return 0;
	}
	return 1;
}

质数的筛选

Eratosthenes 筛法

O(NloglogN)O(N\log\log N)

bool v[N];
void Eratosthenes(int n){
    memset(v,0,sizeof(v));
    for(int i=2;i<=n;i++){
        if(v[i])
            continue;
        for(int j=i;j<=n/i;j++)
            v[i*j]=1;
    }
}

vi=0v_i=0i2i\ge2,则 ii 是质数。

线性筛法

O(N)O(N)

int m;
int v[N],prime[N];
void Q_prime(int n){
	m=0;
	memset(v,0,sizeof(v));
	for(int i=2;i<=n;i++){
		if(!v[i])
			prime[++m]=v[i]=i;
		for(int j=1;j<=m;j++){
			if(prime[j]>v[i]||prime[j]>n/i)
			    break;
			v[i*prime[j]]=prime[j];
		}
	}
}

prime1mprime_{1\sim m} 就是 nn 以内的质数。

质因数分解

O(N)O(\sqrt N)

int m;
int factor[1600];
void q_factor(int n){
	m=0;
    for(int i=2;i*i<=n;i++)
        while(!(n%i))
        	n/=(factor[++m]=i);
	if(n>1)
		factor[++m]=n;
}

factor1mfactor_{1\sim m} 就是分解后的结果。

Pollard-Rho 算法

可在 O(n14)O(n^{\frac{1}{4}}) 的时间内求出 nn 的最大质因子。

需要Miller-Rabin 算法

宏定义

  • #define get(x)\texttt{\#define get(x)}1x1\sim x 的随机数。

变量

  • long long ans\texttt{long long ans}:最大质因子。

函数

  • Pollard_Rho()\texttt{Pollard\_Rho()}:初始化随机种子。
  • ll gcd(ll x,ll y)\texttt{ll gcd(ll x,ll y)}x,yx,y 的最大公约数。
  • ll work(ll x,ll y)\texttt{ll work(ll x,ll y)}:将 xx 分解为两数之积。
  • void solve(ll x,int t)\texttt{void solve(ll x,int t)}:计算 xx 的最大质因子。
  • ll ask(ll x))\texttt{ll ask(ll x))}:询问 xx 的最大质因子。

代码

struct Pollard_Rho{
	ll ans;
	Pollard_Rho(){srand(time(0));}
	ll gcd(ll x,ll y){
		return y?gcd(y,x%y):x;
	}
	#define get(x) (1LL*rand()*rand()*rand()*rand()%(x)+1)
	ll work(ll x,ll y){
		int t=0,k=1;
		ll v0=get(x-1),v,d,s=1;
		v=v0;
		while(1){
			v=(mul(v,v,x)+y)%x;
			s=mul(s,abs(v-v0),x);
			if(!(v^v0)||!s)return x;
			t++;
			if(t%127==0)if((d=gcd(s,x))^1)return d;
			if(t==k){
				if((d=gcd(s,x))^1)return d;
				v0=v;k<<=1;
			}
		}
	}
	void solve(ll x,int t){
		if(!(x^1)||x<=ans)return;
		if(Miller_Rabin(x)){
			if(ans<x)ans=x;
			return;
		}
		ll y=x;
		do{y=work(x,t--);}while(!(y^x));
		while(!(x%y))x/=y;
		solve(x,t);solve(y,t);
	}
	ll ask(ll x){
		ans=0;solve(x,302627441);return ans;
	}
}pr;

back

posted @ 2021-08-15 15:33  luckydrawbox  阅读(15)  评论(0)    收藏  举报  来源