数论基础模板

这篇博客介绍了数论的基础知识,包括中国剩余定理、快速幂取模、欧拉函数、费马小定理、组合数、全错位排序、斯特林数(第一类和第二类)以及Lucas定理。内容涵盖了这些概念的定义、应用和计算方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中国剩余定理

这里写图片描述

//模板
int exgcd(int a,int b,int &x,int &y)    //扩展欧几里得算法 c = ax + by   gcd(a,b)|c
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int d = exgcd(b,a%b,y,x);
    y -= a/b*x;
    return d;
}

int ChineseRemainder(int a[],int w[],int len)    // a[]存放余数  w[]存放两两互质的数
{
    int x,y,m,n=1,ret=0;
    for (int i=0; i<len; i++)
        n *= w[i];
    for (int i=0; i<len; i++)
    {
        m = n/w[i];
        int d = exgcd(w[i],m,x,y);
        ret = (ret+y*m*a[i])%n;
    }
    return (n+ret%n)%n;
}

快速幂取模

long long  PowMod(long long a,long long n,long long m) // a^n%m
{
    long long res = 1;
    while( n!=0 )
    {
        if (n&1)
            res = res * a % m;
        a =a*a%m;
        n = n>>1;
    }
    return res;
}

欧拉函数

对正整数n,欧拉函数表示小于n的正整数中与n互质的数的数目 φ(1)=1

const int N = 1000005;
int phi[N];
vector<int> prime;
void init()  //欧拉函数筛  O(n) + O(1)
int main()
{
    phi[1] = 1;
    for(int i=2; i<N; i++)
    {
        if(phi[i] == 0)
        {
            prime.push_back(i);
            phi[i] = i-1;
        }
        for(int j=0; j<prime.size() && prime[j]*i<N; j++)
        {
            if(i%prime[j] == 0)
            {
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }
            else
                phi[i*prime[j]] = phi[i] * (prime[j]-1);
        }
    }
}

费马小定理

费马小定理

组合数

C(n,m) = n! / ( (n-m)! * m! )(n>=m)

long long  Cnm(int n, int m)// n个中取m个
{
    if (m == 0)
        return 1;
    long long  up = 1;
    long long  down = 1;
    for (int i=0; i<m; i++)
    {
        up *= (n - i);
        down *= (i + 1);
    }
    return up / down;
}

全错位排序

一个人写了n封不同的信及相应的n个不同的信封,他把这n封信都装错了信封,问都装错信封的装法有多少种?
由递推公式得

long long  f[30];
void init()
{
    for(int i=2; i<=25; i++)
    {
        if(i & 1)
            f[i] = i * f[i-1] - 1;
        else
            f[i] = i * f[i-1] + 1;
    }
}

第一类斯特林数

把一个包含n个元素的集合分成k个环排列的方法数。
假设已经推出了n-1个元素分成k个环的方法数以及n-1个元素分成k-1个环的元素,我们考虑第n个元素,一种情况是这个元素自己成环,于是是S(n-1,k-1),另一种情况是把这个元素放到任意一个元素的左边,方案数是(n-1)S(n-1,k).
初始值
S[n][0] = 0, S[1][1] = 1;
递推公式
S[n][k] = S(n-1,k-1) + (n-1)S(n-1,k)

long long stir[maxn][maxn];
void init()
{
    stir[1][1] = 1;
    for(int i=2; i<maxn; i++)
        for(int j=1;j<=i; j++)
            stir[i][j] = stir[i-1][j-1] + (i-1) *stir[i-1][j];

}
第二类斯特林数

把一个包含n个元素的集合分成k个非空子集的方法数。
考虑第n个元素,如果它自成一个集合,那么前n-1个元素构成k-1个集合,就是S(n,k),如果它不是自成集合,那么前面n-1个元素构成k个集合,再把第n个元素加到任意一个集合中,共k种方案。
初始值 S[n][0]=0, S[n][k]=0 (n

Lucas

C(n,m)%p=C(n/p,m/p) * C(n%p,m%p) % p p为素数

long long fac[maxn];
void init(long long mod)
{
    fac[0] = 1;
    for(int i=1; i<=mod; i++)
        fac[i] = fac[i-1] * i % mod;
}
long long lucas(long long n, long long m, long long p)
{
    long long ret = 1;
    while(n && m)
    {
        long long a = n%p;
        long long b = m%p;
        if(a < b)
            return 0;
        ret = (ret * fac[a] * PowMod(fac[b]*fac[a-b]%p, p-2, p)) %p;
        n /= p;
        m /= p;
    }
    return ret;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值