博客园 首页 私信博主 显示目录 隐藏目录 管理

【模板】数论

公约数
gcd

LL gcd(LL a,LL b){
    return b==0? a:gcd(b,a%b);
}

ex_gcd

//返回值为最大公约数
LL ex_gcd(LL a,LL b,LL &x,LL &y){
    LL d = a;
    if(!b){x = 1,y = 0;}
    else{
      d = ex_gcd(b,a%b,y,x);
      y-=a/b*x;
    }
    return d;
}

素数

素因子分解

线性筛

void xxs(){
    int tot = 0;
    memset(check, 0, sizeof(check));
    for (int i = 2; i < MAXL; ++i){
        if (!check[i]){
            prime[tot++] = i;
        }
        for (int j = 0; j < tot; ++j){
            if (i * prime[j] > MAXL) break;
    	    check[i*prime[j]] = 1;
     	    if (i % prime[j] == 0) break;
    }
}

朴素算法\(O(\sqrt n)\)

void prime_factor(int n,map<int,int> &pf){
    for(int i =2 ; i*i<=n ; ++i){//n为素数时!
        while(n%i==0){
            ++pf[i];
            n/=i;
        }
    }
    if(n!=1)pf[n] = 1;
}

Eratosthenes筛法

void Eratosthenes(int n){
    memset(is_prime,true,sizeof(is_prime));

    for(int i = 2 ; i*i<=n; ++i)
        if(is_prime[i])
        for(int j=i*i ; j<=n ; j+=i)is_prime[j] = false;
}

区间筛法

void segment_sieve(LL a,LL b){//[a,b]
    memset(is_prime_ab,true,sizeof(is_prime_ab[0])*(b-a+1));
    memset(is_prime_sqrtb,true,sizeof(is_prime_sqrtb[0])*(sqrt(b)+2));
    for(LL i = 2 ; i*i<=b ; ++i)
    if(is_prime_sqrtb[i]){
        for( LL j = i*i ; j*j<=b ; j+=i)is_prime_sqrtb[j] = false;
        for(LL j = max(i*i,(a-1)/i+1)*i ; j<=b ; j+=i)is_prime_ab[j-a] = false;
    }
}

大素数分解与大素数测试

miller_rabin

已知最快的素数分解算法.\(O(lgV)\)

bool witness(LL a,LL n,LL u,LL t){
	LL x0 = power_mod(a,u,n),x1;
	for(int i=1 ;i<=t ; ++i){
		x1 = mulmod(x0,x0,n);
		if(x1==1 && x0!=1 && x0!=n-1)
			return false;
		x0 = x1;
	}
	if(x1 !=1)return false;
	return true;
}

bool miller_rabin(LL n, int times = 20){
	if(n<2)return false;
	if(n==2)return true;
	if(!(n&1))return false;
	LL u = n-1,t =0;
	while (u%2==0) {
		t++;u>>=1;
	}
	while (times--) {
		LL a = random(1,n-1);
		//if(a == 0)std::cout << a << " "<<n<< " "<<u<<" " << t<<'\n';
		if(!witness(a,n,u,t))return false;
	}
	return true;
}

pollard_rho 分解一个合数\(V\)的运行时间\(O(V^{1/4 })\)

/*
*pollard_rho分解n,
*c : 随机迭代器,每次运行设置为随机种子往往更快.
*/
LL pollard_rho(LL n,LL c = 1){
	LL x  = random(1,n);
	LL i =1,k =2,y = x;
	while (1) {
		i++;
		x = (mulmod(x,x,n)+c)%n;
		LL d = gcd(y-x>=0?y-x:x-y,n);
		if(d!=1 && d!=n)return d;//非平凡因子.
		if(y==x)return n;//重复.
		if(i==k){ y = x ; k<<=1;}//将x_1,2,4,8,16,..赋值为y.
	}
}
找出因子分解 $O(V^{1/4}lgV)$
void find_factor(LL n,std::map<LL, int>  & m){
	if(n<=1)return ;
	if(miller_rabin(n)){
		++m[n];
		return ;
	}
	LL p = n;

	while (p==n)p = pollard_rho(p,random(1,n));
	find_factor(p,m);
	find_factor(n/p,m);
}

euler phi函数

\[\phi(n) = n\prod_{i = 1}^{k}(1-\frac{1}{p_i}) \]

证明详见《初等数论及其应用》

int  euler_phi(int  n){
    int  ans = n;
    for(int i=2 ; i*i<=n ; ++i)
        if(ans%i ==0)
        {
            ans = ans/i*(i-1);
            while(n%i==0)n/=i;
        }
        if(n>1)ans = ans/n*(n-1);
    return ans;
}

phi_table,类似于线性筛的做法

void phi_table(int n){
    memset(phi,0,sizeof(phi[0])*(n+5));
    phi[1] = 1;
    for(int i = 2 ; i<=n ; ++i){
        if(!phi[i]){//素数标记
            for(int j = i ; j<=n ; j+=i){
                if(!phi[j])phi[j] = j;
                phi[j] = phi[j]/i*(i-1);
            }
        }
    }
}

模运算
power_mod

LL power_mod(LL x,LL n,LL mod){
    LL res = 1;
    while(n){
        if(n&1)res = (res*x)%mod;
        x = (x*x)%mod;
        n>>=1;
    }
    return res;
}

大数乘法取模

LL mulmod(LL a,LL b,LL mod){
	LL res =0,y = a%mod;
	while (b) {
		if(b&1)res = (res+y)%mod;
		b>>=1;
		y = (y<<1)%mod;
	}
	return res;
}

大整数取模

LL big_mod(string val,LL mod){
    LL res = 0;
    for(int i=0 ; i<val.length() ; ++i){
        res = ((res)*10+val[i]-'0')%mod;
    }
    return res;
}

模方程

LL MLE(LL a,LL b,LL n){
    LL d,x,y;
    d = ex_gcd(a,n,x,y);
    if(b%d !=0){
        return -1;
    }else{
        LL x0 = x*b/d%n+n;
        return x0%(n/d);//模(n/d)
    }
}

乘法逆元 a在模n意义下的逆

LL inv(LL a,LL n){
    LL x,y;
    LL d = ex_gcd(a,n,x,y);
    return d==1? (x+n)%n:-1;//非负性保证.
}

中国剩余定理

//x % m[i] = a[i]
LL china(int n,int *a,int *m){
    LL M = 1,x = 0,y,z;
    for(int i=0 ; i<n ; ++i)M*=m[i];
    for(int i=0 ; i<n ; ++i){
        LL M_i = M/m[i];
        ex_gcd(M_i,m[i],y,z);//M_i*y = 1(mod m[i])
        x = (x+M_i*a[i]*y)%M;
    }
    return (x+M)%M;
}

朴素模方程(\(m_i不两两互素的时候\))

LL MLE(int *r,int *mod,int n){
	LL lm = 0, lb = 1;
	for (int i = 0; i < n; i++)
	{
		LL k1,k2;
		LL d= exgcd(lb, mod[i],k1,k2);	// x=c1(mod r1)
		if ((lm - r[i]) % d) { return -1; }	// 联立x=r2(mod m2),(r1-r2)=0(mod gcd)才有解
		lb = lb / d * mod[i];							// lcm
		LL z = k2 * ((lm - r[i]) / d);						// 求出k2
		lm = z * mod[i] + r[i];											// 得到方程组的一个最小解
		lm = ((lm % lb) + lb) % lb;										// 保证最小解大于0
	}
	return lm;
}

莫比乌斯反演 线性筛法\(O(n)\)

int prime[maxn],cnt;
int mu[maxn];

void init_mobius(){
    memset(prime,0,sizeof(prime));
    mu[1] =1;
    cnt =0;
    for(int i=2 ;i<maxn ; ++i){
        if(!prime[i]){
            prime[cnt++] = i;
            mu[i] = -1;
        }
        for(int j=0 ; j<cnt && i*prime[j]<maxn ; ++j){
            prime[i*prime[j]] = 1;
            if(i%prime[j])mu[i*prime[j]] = -mu[i];
            else {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}
posted @ 2017-10-19 15:10  Hanser  阅读(168)  评论(0编辑  收藏  举报