初等数论合集

typedef long long LL;

组合数 

LL C(LL n, LL m)
{
    if (m < n - m)
        m = n - m;
    LL ans = 1;
    for (LL i = m + 1; i <= n; i++)
        ans = ans * i % mod;
    for (LL i = 1; i <= n - m; i++)
        ans = ans * Inv(i, mod) % mod; // 不取mod 改成 / i
    return ans;
}

欧拉筛法即线性筛

const int maxm = 10000000 + 5;
bool isprime[maxm]; //若1为素数 若0不是素数
int su[maxm];
int cnt = 0;
void prime()
{
    memset(isprime, true, sizeof isprime);
    memset(su, 0, sizeof su);
    isprime[0] = isprime[1] = false; // 0 和 1 不是素数
    for (int i = 2; i <= maxm; i++)
    {
        if (isprime[i])
            su[++cnt] = i;
        for (int j = 1; j <= cnt && i * su[j] <= maxm; j++)
        {
            isprime[i * su[j]] = false;
            if (i % su[j] == 0)
                break;
        }
    }
}

欧几里德 

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

扩展欧几里德

int ex_gcd(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    else
    {
        int d = ex_gcd(b, a % b, x, y);
        int t = x;
        x = y;
        y = t - (a / b) * y;
        return d;
    }
}

快速幂

LL qpow(LL a, LL b, LL c)
{
    LL ans = 1;
    while (b)
    {
        if (b & 1)
            ans = ans * a % c;
        a = a * a % c;
        b = b >> 1;
    }
    return ans;
}

快速乘

LL qmul(LL a, LL b)
{
    LL ans = 0;
    while (b)
    {
        if (b & 1)
            ans = ans + a;
        a = a * 2;
        b = b >> 1;
    }
    return ans;
}

乘法逆元

这位博主说得挺好的https://www.cnblogs.com/zjp-shadow/p/7773566.html

扩展欧几里德求逆元

void Ex_gcd(LL a, LL b, LL &x, LL &y)
{
    if (!b)
        x = 1, y = 0;
    else
        Exgcd(b, a % b, y, x), y -= a / b * x;
}
int main()
{
    LL x, y;
    Ex_gcd(a, p, x, y);
    x = (x % p + p) % p;
    printf("%d\n", x); //x是a在mod p下的逆元
}

费马小定理即快速幂求逆元

LL Inv(LL a, LL p)
{
    return qpow(a, p - 2, p);
}

线性递推求逆元

LL n, p;
    cin >> n >> p;
    inv[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        inv[i] = p - p / i * inv[p % i] % p;
    }

质因数分解

int a[maxn]; // a[i] 表示 第i个质因数的值
int b[maxn]; // b[i] 表示第i个质因数的指数
int tot;     // 不同的质因数的个数
void factor(int n, int *a, int *b, int &tot)
{
    tot = 0;
    int t, now = n;
    t = (int)((double)sqrt(n) + 1);
    for (int i = 2; i <= t; i++)
    {
        if (now % i == 0)
        {
            a[++tot] = i;
            b[tot] = 0;
            while (now % i == 0)
            {
                ++b[tot];
                now /= i;
            }
        }
    }
    if (now != 1)
    {
        a[++tot] = now;
        b[tot] = 1;
    }
}

欧拉函数(小于n且与n互素的整数个数)

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

1~n中所有数的欧拉phi函数值 O(nloglogn)

void phi_table(int n)
{
    for (int i = 2; i <= n; i++)
        phi[i] = 0;
    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);
            }
        }
    }
    return;
}

筛完素数后求因子个数 跟上面的欧拉筛是配合的

LL count_divisor(LL n)
{
    LL s = 1;
    for (int i = 0; i <= cnt && su[i] * su[i] <= n; i++)
    {
        if (n % su[i] == 0)
        {
            LL a = 0;
            do
            {
                n = n / su[i];
                a++;
            } while (n % su[i] == 0);
            s = s * (a + 1);
        }
    }
    if (n > 1)
        s = s * 2;
    return s;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值