• OI数论模板总结


    1.欧几里得算法

    可以通过欧几里得算法求出最大公因子。

    int gcd(int x, int y) //欧几里得算法 
    { 
        return y==0 ?  x : gcd(y, x%y);
    }
    

    2.扩展欧几里得

    可以通过扩展欧几里得求出(ax+by=d)不定方程的一组整数解。(a, b, d为正整数)

    void exgcd(int a, int b, int& x, int& y) //扩展欧几里得 
    {
        if(!b)
        {
        	x=1; y=0;
         	return ;
    	}
    	exgcd(b, a%b, y, x);
    	y-=(a/b)*x; 
    }
    

    3.快速幂

    可以通过快速幂在(O(logn))的复杂度下求出(x^y\%p)

    LL ksm(LL x, LL y, int p) //快速幂 
    {
    	LL ans=1;
    	while(y)
    	{
    		if(y&1) ans=(ans*x)%p;
    		y>>=1; x=(x*x)%p;
    	}
    	return ans%p;
    }
    
    

    4.质因数分解

    可以求出一个整数的所有质因数(没有去重)

    void factor(int num) //质因数分解 
    {
    	int fac[MAXN],cnt;
    	while(num!=1)
    		for(int i=2; i<=num; i++) if(num%i==0)
    		{
    			fac[++cnt]=i;
    			num/=i; i=1;
    		}
    	for(int i=1; i<=cnt; i++) printf("%d ",fac[i]);
    }
    

    5.费马小定理求组合数

    可以求$C(n, m)%p $ 其中需要(n,m)较小,较大时要用卢卡斯定理优化。

    LL combine(LL x, LL y)   //费马小定理求组合数 
    {  
        LL up=1, down=1;  
        for(LL i=0; i<y; i++)
    	{  
            up=up*(x-i)%p;  
            down=down*(i+1)%p;  
        }  
        return up*ksm(down, p-2, p)%p;  //可以直接使用上文给出的ksm()
    }  
    

    6.卢卡斯定理求组合数

    同样可以求$C(n, m)%p $ 其中 $p<=10^5 $ $ n, m<=10^{18}$。

    LL lucas(LL x, LL y) //卢卡斯定理求组合数 
    {  
        if(!y) return 1;  
        return combine(x%p, y%p)*lucas(x/p, y/p)%p;  //可以直接使用上文给出的combine()
    }  
    

    7.中国剩余定理

    可以求解一元线性同余方程组。

    LL china(int n, int *a, int *m) //中国剩余定理 
    {
        LL p=1, ret=0, x, y;
        for(int i=1; i<=n; i ++) p*=m[i];
        for(int i=1; i<=n; i ++)
    	{
            LL w=p/m[i];
            exgcd(m[i], w, x, y); //可以直接使用上文的exgcd()
            ret=(ret+w*y*a[i])%p;
        }
       return (ret+p)%p;
    }
    

    8.线性素数筛

    可以求出1-num内所有的素数。

    void prime(int num) //素数筛 
    {
    	int cnt=0, check[MAXN], pri[MAXN];
    	sizeof(check, true, sizeof(check));
    	check[1]=false;
    	for(int i=2; i<=num; i++)
    	{
    		if(check[i]) pri[++cnt]=i;
    		for(int j=0; j<cnt && i*pri[j]<=num; j++)
    		{
    			check[i*pri[j]]=false;
    			if(i%pri[j]==0) break;
    		}
    	}
    } 
    

    9.欧拉函数筛

    可以求出1-num内的欧拉函数。

    void euler(int num) //欧拉函数筛 
    {     
        int cnt=0, check[MAXN], eul[MAXN], pri[MAXN];
    	sizeof(check, true, sizeof(check));  
    	check[1]=false; eul[1]=1;  
        for(int i=2; i<=num; i++)
    	{
    		if(check[i])
    		{
    			pri[++cnt]=i;
    			eul[i]=i-1;
    		}
    		for(int j=0; j<cnt && i*pri[j]<=num; j++)
    		{
    			check[i*pri[j]]=false;
    			if(i%pri[j]==0)
    			{
    				eul[i*pri[j]]=eul[i]*pri[j];
    				break;
    			}
    			eul[i*pri[j]]=eul[i]*(pri[j]-1);
    		}
    	}      
    }
    

    10.莫比乌斯函数筛

    可以求出1-num内的莫比乌斯函数

    void mobius(int num) //莫比乌斯函数筛 
    {
    	int cnt=0, check[MAXN], mob[MAXN], pri[MAXN];
    	sizeof(check, true, sizeof(check));
    	check[1]=false; mob[1]=1;  
        for(int i=2; i<=num; i++)
    	{
    		if(check[i])
    		{
    			pri[++cnt]=i;
    			mob[i]=-1;
    		}
    		for(int j=0; j<cnt && i*pri[j]<=num; j++)
    		{
    			check[i*pri[j]]=false;
    			if(i%pri[j]==0)
    			{
    				mob[i*pri[j]]=0;
    				break;
    			}
    			mob[i*pri[j]]=-mob[i];
    		}
    	}  
    }
    
  • 相关阅读:
    JavaScript中循环的使用方法
    认识了解JavaScript
    div的对齐显示
    四宫格div
    使用div写一个计算机
    div基本操作
    CSS样式
    Electron的逆向
    Electron输出:Hello,World
    Electron的安装-Windows
  • 原文地址:https://www.cnblogs.com/CrazyDave/p/8484776.html
Copyright © 2020-2023  润新知