数论板子

线性筛

void get_primes(int n){
    for (int i = 2; i <= n; i ++ ){
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ ){
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

n! 的约数个数

int res = 1;
for (int i = 0; i < cnt; i ++ ){
    int p = primes[i];
    int s = 0;
    for (int j = n; j; j /= p) s += j / p;
    res = (LL)res * (2 * s + 1) % mod;
}

约数之和

LL res = 1;
for (auto p : primes){
    LL a = p.first, b = p.second;
    LL t = 1;
    while (b -- ) t = (t * a + 1) % mod;
    res = res * t % mod;
}

用到了秦九韶算法

f(x)=a0 + a1x + a2x2 + a3x3 + ⋯ + anxn

f(x)=((⋯(anx + an−1)x + an−2)x + ⋯+a1)x + a0


最大公约数

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

欧拉函数

int res = n;
for(int i = 2;i <= n / i;i ++)
    if(n % i == 0){
        res = res / i * (i - 1);
        while(n % i == 0) n /= i;
    }
if(n > 1) res = res / n * (n-1);

素数筛 + 欧拉函数

int primes[N], cnt;
int euler[N];
bool st[N];

void get_eulers(int n){
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ ){
        if (!st[i]){
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ ){
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0){
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

快速幂

LL qmi(int a, int b, int p) {
    LL res = 1 % p;
    while (b){
        if (b & 1) res = res * a % p;
        a = a * (LL)a % p;
        b >>= 1;
    }
    return res;
}

矩阵快速幂

acwing.1305.GT考试

#include <cstring>//矩阵快速幂
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25;

int n, m, mod;
char str[N];
int ne[N];
int a[N][N];

void mul(int c[][N], int a[][N], int b[][N]) {  // c = a * b
    static int t[N][N];
    memset(t, 0, sizeof t);

    for (int i = 0; i < m; i ++ )
        for (int j = 0; j < m; j ++ )
            for (int k = 0; k < m; k ++ )
                t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % mod;

    memcpy(c, t, sizeof t);
}

int qmi(int k){
    int f0[N][N] = {1};
    while (k){
        if (k & 1) mul(f0, f0, a);  // f0 = f0 * a
        mul(a, a, a);  // a = a * a
        k >>= 1;
    }

    int res = 0;
    for (int i = 0; i < m; i ++ ) res = (res + f0[0][i]) % mod;
    return res;
}

int main()
{
    cin >> n >> m >> mod;
    cin >> str + 1;

    // kmp
    for (int i = 2, j = 0; i <= m; i ++ ){
        while (j && str[j + 1] != str[i]) j = ne[j];
        if (str[j + 1] == str[i]) j ++ ;
        ne[i] = j;
    }

    // 初始化A[i][j]

    for (int i = 0; i < m; i ++ )
        for (int c = '0'; c <= '9'; c ++ ){
            int j = i;
            while (j && str[j + 1] != c) j = ne[j];
            if (str[j + 1] == c) j ++ ;
            if (j < m) a[i][j] ++;
        }


    // F[n] = F[0] * A^n
    cout << qmi(n) << endl;

    return 0;
}

扩展欧几里得
裴蜀定理

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

组合数C ( DP求解 ) ( 复杂度 N ^2 )

void init(){
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j <= i; j ++ )
            if (!j) c[i][j] = 1;
            else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}


组合数C ( 阶乘 + 逆元 ) ( 复杂度 N * logN)

int qmi(int a, int k, int p){
    int res = 1;
    while (k){
        if (k & 1) res = (LL)res * a % p;
        a = (LL)a * a % p;
        k >>= 1;
    }
    return res;
}

void jie(){
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i ++ ){
        fact[i] = (LL)fact[i - 1] * i % mod;
        infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
        //infact[i] = (LL)qmi(fact[i], mod - 2, mod) % mod; 这两行都行
    }
}

printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);//输出Cab

组合数C ( 卢卡斯定理 ) ( 复杂度 mod * log mod)

int lucas(LL a, LL b, int p){
    if (a < p && b < p) return C(a, b, p);
    return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
    //这里的C函数根据数据量变化而改变
    //单组查询,直接计算即可
    //多组数据,预处理阶乘
}

求组合数 IV ( 高精度 + 分解质因数 )

acwing.1315.网格

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;

const int N = 5050;

int a, b;

vector <int> res;
int primes[N], cnt;
int st[N];

void init(int t) {
    for(int i = 2;i <= t;i ++) {
        if(st[i] == 0) primes[cnt ++] = i;
        for(int j = 0;i * primes[j] <= t;j ++) {
            st[i * primes[j]] = 1;
            if(primes[j] % i == 0) break;
        }
    }
}

int get(int n, int p) {
    int ret = 0;
    while(n){
        ret += n/p;
        n /= p;
    }
    return ret;
 }

vector <int> mul(vector <int> v, int t) {
    int num = 0;
    for(int i = 0;i < v.size();i ++) {
        num += v[i] * t;
        v[i] = num % 10;
        num /= 10;
    }
    while(num) {
        v.push_back(num % 10);
        num /= 10;
    }
    return v;
}

int main(){
    cin >> a >> b;
    init(a);

    res.push_back(1);
    for(int i = 0;i < cnt;i ++) {
        int l = get(a, primes[i]) - get(b, primes[i]) - get(a-b, primes[i]);
        while(l){
            res = mul(res, primes[i]);
            l --;
        }
    }

    for(int i = res.size() - 1;i >= 0;i --) printf("%d", res[i]);

    puts("");

    return 0;
}

证明: l c m ( S a , S b ) = S g c d ( a , b ) lcm(\frac{S}{a}, \frac{S}{b})=\frac{S}{gcd(a, b)} lcm(aS,bS)=gcd(a,b)S

l c m ( S a , S b ) = S ∗ l c m ( 1 a , 1 b ) = S ∗ ( a ∗ b ) ∗ l c m ( 1 a , 1 b ) ( a ∗ b ) = S ∗ l c m ( b , a ) ( a ∗ b ) = S ( a ∗ b ) l c m ( b , a ) = S g c d ( a , b ) lcm(\frac{S}{a}, \frac{S}{b})=S*lcm(\frac{1}{a}, \frac{1}{b})=\frac{S*(a*b)*lcm(\frac{1}{a}, \frac{1}{b})}{(a*b)}=\frac{S*lcm(b, a)}{(a*b)}=\frac{S}{\frac{(a*b)}{lcm(b, a)}}=\frac{S}{gcd(a, b)} lcm(aS,bS)=Slcm(a1,b1)=(ab)S(ab)lcm(a1,b1)=(ab)Slcm(b,a)=lcm(b,a)(ab)S=gcd(a,b)S

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值