常用数论算法

扩展欧几里得:解不定方程,求逆元

int extended_gcd(int a, int b, int &x, int &y) {
 	   int r, tmp; 
	   if (b==0) {  x = 1;  y = 0;  return a; }
	   r = extended_gcd(b, a % b, x, y); 
 	   tmp = x;  x = y;  y = tmp - a / b * y;
      return r; 
} 

求ax ≡ 1 (mod n)的乘法逆元,若不存在,返回-1

long long Inverse(long long a,long long n)
{
      long long x,y;
      if(extended_gcd(a,n,x,y)==1)return (x+n)%n; else return -1;
}


欧拉函数:

单个欧拉函数:时间复杂度o(sqrt(n))

int euler(int x)                                //计算φ(x)
{
     int i,ans= x, a = x;                     //找出所有x的质因数
     for(i = 2; i*i<= a; i++)              //从2讨论到sqrt(n)即可
     {
            if(a%i == 0)                       //i为x的质因数
            {
                  ans = ans-ans/i;              //φ(x) = x*(1 - 1/p1)*(1 - 1/p2)......
                  while(a%i == 0) a=a/i;   //算术基本定理,抹掉i^1,i^2,i^3....
            }
     }
     if(a > 1) ans =ans - ans/a;            //存在大于sqrt(a)的质因子
     return ans;
}
线性筛欧拉函数:

void getPhi()
{
	int i,j,tot=0;
	for(i=2;i<=MaxN;i++)              {
		if(Mark[i]==false){  Prime[++tot]=i;  phi[i]=i-1;  }//当 i 是素数时 phi[i]=i-1
		for(j=1; j<=tot&&i*Prime[j]<=MaxN; j++)                           {
			Mark[i*Prime[j]]=true;            
			if(i%Prime[j]==0)                                {   
				phi[i*prime[j]]=phi[i]*prime[j];   break;
			 }            //如果i mod p = 0, 那么 phi[i * p]=p * phi[i] 
			else   phi[i*Prime[j]]=phi[i]*(Prime[j]-1);
		}//其实这里Prime[j]-1就是phi[Prime[j]],利用了欧拉函数的积性  
     	}             
}
既然写到线性筛了,那就写完。

线性筛质数:

void getPrime()
{
       int i,j,tot=0;
       for(i=2;i<=MaxN;i++)
      {
         	if(Mark[i]==false)Prime[++tot]=i;
         	for(j=1; j<=tot&&i*prime[j]<=MaxN; j++)             {
             		Mark[i*Prime[j]]=true;  //Prime[j]是合数i*Prime[j]的最小质因数            
             		if(i%Prime[j]==0) break;  
        	}            // ↑ 比一个合数大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
     }
}
线性筛一个数的因数个数:

void pre(){
	int i,j; 
	d[1]=1; 
	for(i=2;i<=b;i++){
		if(!mark[i]){prime[++tot]=i;temp[i]=1;d[i]=2;}
		for(j=1;j<=tot&&i*prime[j]<=b;j++){
			mark[i*prime[j]]=true;
			if(i%prime[j]==0){
				d[i*prime[j]]=d[i]/(temp[i]+1)*(temp[i]+2);
				temp[i*prime[j]]=temp[i]+1;
				break;
			}
			else{
				d[i*prime[j]]=d[i]*d[prime[j]];
				temp[i*prime[j]]=1;
			} 
		}
	}
}

二分快速幂:x^y%z;

long long mont(long long x,long long y,long long z){
	long long temp=1;
	for(x%=z;y;y>>=1,x=(x*x)%z){
		if(y&1)temp=(temp*x)%z;
	}
	return temp;
}
矩阵乘法模板:

#include<cstdio> 
#include<iostream> 
#include<algorithm> 
#include<cstdlib> 
#include<cstring> 
#define mod m 
using namespace std; 
typedef long long arr[10][10]; 
arr a,b,z,ans,map; 
long long n,m; 
void multiply(arr x,arr y){ 
    memset(z,0,sizeof(z)); 
    for(long long i=1;i<=5;i++){ 
        for(long long j=1;j<=5;j++){ 
            for(long long h=1;h<=5;h++){ 
                z[i][j]=(z[i][j]+x[i][h]*y[h][j]%mod)%mod; 
            } 
        } 
    } 
    memcpy(x,z,sizeof(z)); 
} 
void mont(long long t){ 
    memset(ans,0,sizeof(ans)); 
    for(long long i=1;i<=5;i++)ans[i][i]=1; 
    while(t>0){ 
        if(t&1)multiply(ans,b); 
        t>>=1; 
        multiply(b,b); 
    } 
} 
int main(){ 
    long long i,j; 
    scanf("%I64d%I64d",&n,&m); 
    if(n==1){ 
        cout<<"2";return 0; 
    } 
    if(n==2){ 
        cout<<"5";return 0; 
    } 
	b[1][5]=1;
	b[2][2]=1;
	b[2][5]=2;
	b[3][4]=b[3][5]=1;
	b[4][3]=1;
	b[5][1]=b[5][2]=b[5][3]=b[5][5]=1;
	a[1][1]=1;
	a[1][2]=2;
	a[1][3]=1;
	a[1][4]=1;
	a[1][5]=5;
    mont(n-2); 
    multiply(a,ans); 
    cout<<a[1][5];
}
关于杨辉三角和组合数:

单个:

long long C(long long n,long long m){
	int i,j;
	a=1;
	b=1;
	if(m>n/2)m=n-m;
	for(i=n,j=1;j<=m;i--,j++){
		a*=i;
		b*=j;
		if(a%b==0){
			a/=b;
			b=1;
		}
	}
	return a/b;
}

一排:组合数取模o(nlogn)

zuhe[0]=1;
zuhe[1]=t;
for(i=2;i<t;i++){
	long long x,y,a,b;
	long long niyuan=mont(i,mod-2,mod);
	zuhe[i]=zuhe[i-1]*niyuan%mod*(t-i+1)%mod;
}
zuhe[t]=1;
还有一种,先预处理1--t的阶乘,直接弄,当然也要求逆元!o(nlongn)


线性筛质因数个数(重复的算多个):

for(i=2;i<=maxm;i++){
        if(sum[i]==0){
        	prime[++tot]=i;
			sum[i]=1;
		}
        for(j=1;j<=tot&&i*prime[j]<=maxm;j++){
            sum[i*prime[j]]=sum[i]+1;
            if((i%prime[j])==0)break;
        }


线性筛莫比乌斯函数:

void pre(){
	int i,j;
	mobius[1]=1;
	for(i=2;i<=50000;i++){
		if(mark[i]==false){
			prime[++tot]=i;
			mobius[i]=-1;
		}
		for(j=1;j<=tot&&i*prime[j]<=50000;j++){
			mark[i*prime[j]]=true;
			if(i%prime[j]==0){
				mobius[i*prime[j]]=0;
				break;
			}
			mobius[i*prime[j]]=-mobius[i];
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值