数论模板

一.欧拉筛求素数

for (int i = 2; i <= n; i++)
	{
		if (!pri[i])
			ans[++tot] = i;
		for (int j = 1; (j <= tot) && (i * ans[j] <= n); j++)
		{
			pri[i * ans[j]] = 1;
			if (i % ans[j] == 0)
				break;
		}
	}

二.欧拉函数

#include <bits/stdc++.h>
#define ll long long
const int N = 1e5 + 5;

ll read()
{
	ll x=0;int f=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int phi[N],p[N],cnt,E[N],pri[N];
int getphi(int n)//针对一个数求欧拉函数
                //原理:φ(n)=n*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)……(1-1/pn)
{
    int ans=n;
    for (int i=2;i*i<=n;i++)
    {
        if (n%i==0)
        {
            ans=ans/i*(i-1);
            while (n%i==0) n/=i;
        }
    }
    if (n) ans=ans/n*(n-1);
    return ans;
}

int getphi2(int n)//打表,但较为暴力
{
    for (int i=2;i<=n;i++)
    {
        if (!E[i])
        {
            for (int j=i;j<=n;j+=i)
            {
                if (!E[j]) E[j]=j;
                E[j]=E[j]/i*(i-1);
            }
        }
    }
    return E[n];
}

int getphi3(int n)//用欧拉筛法同时求出素数和欧拉函数
    //若a为素数,b%a==0,phi[a*b]=phi[b]*a
{
    phi[1]=1;
    for (int i=2;i<=n;i++)
    {
        if (!pri[i])//是素数
        {
            p[++cnt]=i;
            phi[i]=i-1;
        }
        for (int j=1;j<=cnt&&p[j]*i<=n;j++)
        {
            pri[p[j]*i]=1;
            if (i%p[j]==0)
            {
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
            else phi[i*p[j]]=phi[i]*(p[j]-1);//a,b互质,欧拉函数为积性函数,phi[a*b]=phi[a]*phi[b]
        }
    }
    return phi[n];
}
int main()
{
    int n=read();
    int a=getphi(n);
    int b=getphi2(n);
    int c=getphi3(n);
    printf("%d %d %d",a,b,c);
    return 0;
}

三,欧拉筛求约数个数和

#include<bits/stdc++.h>//求1~n的约数个数的和
using namespace std;
#define N 1000010
#define ll long long
ll ans;
int n,t[N],e[N],pri[N],pd[N],cnt;
void oula(int n)//t[i]:i的约数个数
{				//e[i]:i的最小质因子的次数,即pmin^k的k
	t[1]=1;
	for (int i=2;i<=n;i++)
	{
		if (!pd[i])
		{
			pri[++cnt]=i;
			t[i]=2;
			e[i]=1;
		}
		for (int j=1;i*pri[j]<=n&&j<=cnt;j++)
		{
			pd[i*pri[j]]=1;
			if (i%pri[j]==0)
			{
				t[i*pri[j]]=t[i]/(e[i]+1)*(e[i]+2);//公式:n=p1^k1 * p2^k2 * p3^k3 ……
												//则n的约数个数为(k1+1)*(k2+1)*(k3+1)……
												//k1的次数(即e[i*pri[j]])更新为k1+1
				e[i*pri[j]]=e[i]+1;
				break;
			}
			else
			{
				t[i*pri[j]]=t[i]*2;//t为积性函数
				e[i*pri[j]]=1;
			}
		}
	}
}		
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin>>n;
	oula(n);
	for (int i=1;i<=n;i++)
		ans+=t[i];
	cout<<ans;
}

四,线性筛求约数和

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define ll long long
ll ans;
int n,t[N],e[N],pri[N],pd[N],cnt;
void oula(int n)//t[i]:i的约数和
{				//e[i]:i的约数中,不能被i的最小质因子整除的约数的 和
	t[1]=1;e[1]=1;
	for (int i=2;i<=n;i++)
	{
		if (!pd[i])
		{
			pri[++cnt]=i;
			t[i]=i+1;
			e[i]=1;
		}
		for (int j=1;i*pri[j]<=n&&j<=cnt;j++)
		{//令S表示i的约数集,S’表示i的约数翻pj倍后的数的集合
			pd[i*pri[j]]=1;
			if (i%pri[j]==0)//如果i是pj的倍数,那么S和S’必有交集T,T=S中pj的倍数
			{//那么t[i*pj]=S+S'-T=S'+S-T=t[i]*pj+e[i]
				t[i*pri[j]]=t[i]*pri[j]+e[i];
				e[i*pri[j]]=e[i];
				break;
			}
			else
			{
				t[i*pri[j]]=t[i]*(pri[j]+1);//积性函数
				//也可以证明:S∩S’=∅,则S和S’中无重复元素
				//t[i*pj]=S+S'=t[i]+t[i]*pj=t[i]*(pj+1)
				e[i*pri[j]]=t[i];
			}
		}
	}
}		
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin>>n;
	oula(n);
	for (int i=1;i<=n;i++)
		ans+=t[i];
	cout<<ans;
}

五,快速幂

ll b,n,k,ans=1;
int main()
{
	b=read();n=read();k=read();
	b%=k;
	while(n)
	{
		if(n&1)ans=(ans*b)%k;
		n>>=1;
		b=(b*b)%k;
	}
	printf("%I64d",ans);
	return 0;
}

六,逆元

  1. 费马小定理求逆元
ll qpow(ll a, ll b)
{
    ll res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res % mod;
}
// 费马小定理 —— a在模p意义下的逆元
ll Inv(ll a, ll p) { return qpow(a, p - 2); }

2.扩展欧几里得求逆元

typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y) //扩展欧几里得算法
{
    if (b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    ll t = exgcd(b, a % b, x, y);
    ll tmp = x;
    x = y;
    y = tmp - a / b * x;
    return t;
}
ll Inv(int a, int mod) //求a在mod下的逆元,不存在逆元返回-1
{
    ll x, y;
    ll d = exgcd(a, mod, x, y);
    return d == 1 ? (x%mod+ mod) % mod : -1; //x可能是负数,转化成正数
}

七,中国剩余定理

#include<bits/stdc++.h>
#define inf 1000000000
#define ll long long
#define N 500010
#define lson rt<<1
#define rson rt<<1|1
#define mo 999911659
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n;
ll x,y,yu[20],pri[20],M=1,ans;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
	if (b==0) {x=1,y=0;return a;}
	ll g=exgcd(b,a%b,x,y);
	int t=x;x=y;y=t-a/b*y;
	return g;
}
int main()
{
	int n=read();
	for (int i=1;i<=n;i++) 
	{
		pri[i]=read();M*=pri[i];
		yu[i]=read();
	}
	for (int i=1;i<=n;i++)
	{
		ll tmp=M/pri[i];
		exgcd(tmp,pri[i],x,y);
		ans=(ans+yu[i]*tmp*x+M)%M;
	}
	printf("%lld",(ans+M)%M);
	return 0;
}

八,Lucas定理

#include<bits/stdc++.h>//求C(n+m,m)
using namespace std;
#define re register int
#define ull unsigned long long
#define ll long long
#define INF 0x3f3f3f3f
#define N 200009
#define lson rt<<1
#define rson rt<<1|1
#define ne e[i].to
#define mo 998244353
#define lowbit(x) (x)&(-(x))
void FRE(){freopen("journalist.in","r",stdin);freopen("journalist.out","w",stdout);}
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();}
    return x*f;
}
typedef pair<int,ll>P;
int n,m,p;
ll fac[100010];
ll ksm(ll a,int b)
{
	ll res=1;
	while (b)
	{
		if (b&1) res=res*a%p;
		a=a*a%p;
		b>>=1;
	}
	return res;
}
ll cal(int a,int b)
{
	if (a<b) return 0;if (!b) return 1;
	return fac[a]*ksm(fac[b],p-2)%p*ksm(fac[a-b],p-2)%p;
}
ll lucas(int x,int y)
{
	if (!y) return 1;if (x<y) return 0;
	return lucas(x/p,y/p)*cal(x%p,y%p)%p;
}
int main()
{
	int T=read();
	while (T--)
	{
		n=read(),m=read(),p=read();
		fac[0]=1;
		for (int i=1;i<=100003;i++) fac[i]=fac[i-1]*i%p;	
		printf("%lld\n",lucas(n+m,m));
	}
	return 0;
}
posted @ 2021-04-08 19:19  蛙蛙1551  阅读(62)  评论(0编辑  收藏  举报