• 算法基础-数学知识-高斯消元、求组合数


    高斯消元

    1. 找到当前列绝对值最大的数 所在的行
    2. 将改行的该列的系数变成1,其他列也要跟着变
    3. 将这行和最上面未处理的那行交换(不是第一行)
    4. 最上面那行的以下的所有行的该列消元
    5. 判断是否存在解 123三种情况
    6. 若有唯一解,则从最下面开始消元

    883. 高斯消元解线性方程组

    #include 
    #include 
    #include 
    
    using namespace std;
    const int N = 110;
    const double eps = 1e-6;//eps是epsilon,表示很小的值
    double a[N][N];
    int n;
    int gauss()
    {
        int c, r;
        for (c = 0, r = 0; c < n; ++ c) // ++ r不能放在这一行,因为不是每一个a[t][c]都合法
        {
            int t = r;
            for (int i = r; i < n; ++ i)
                if (fabs(a[t][c]) < fabs(a[i][c])) 
                    t = i;
            if (fabs(a[t][c]) < eps) continue;//说明就没有未知数Xc,他的系数最大就是0
            //交换
            for (int i = c; i <= n; ++ i) swap(a[t][i], a[r][i]);
            //将这一行的这一列变成1
            for (int i = n; i >= c; -- i) a[r][i] /= a[r][c];//后面的状态需要第一个状态作为基准,因此从后面推
    
            //将下面的行对应的这一列消成0
            for (int i = r + 1; i < n; ++ i)
            {
                if (fabs(a[i][c]) > eps)
                    for (int j = n; j >= c; -- j)
                        a[i][j] -= a[r][j] * a[i][c];
            }
    
            r ++;
        }
        //c此时=n
        if (r < c)// 说明剩下方程的个数是小于 n 的,说明不是唯一解,判断是无解还是无穷多解
        {// 因为已经是阶梯型,所以 r ~ n-1 的值应该都为 0
            for (int i = r; i < n; i ++ )// 
                if (fabs(a[i][n]) > eps)// a[i][n] 代表 b_i ,即 左边=0,右边=b_i,0 != b_i, 所以无解。
                    return 2;
            return 1;// 否则, 0 = 0,就是r ~ n-1的方程都是多余方程
        }
        for (int i = r; i >= 0; -- i)//r此时=n-1
            for (int j = i + 1; j < n; ++ j)
                a[i][n] -= a[i][j] * a[j][n];
                
        return 0;
    }
    void solve()
    {
        cin >> n;
        for (int i = 0; i < n; ++ i)
            for (int j = 0; j <= n; ++ j)
                cin >> a[i][j];   
        int t = gauss();
        if (t == 1) puts("Infinite group solutions");
        else if (t == 2) puts("No solution");
        else  
        {
            for (int i = 0; i < n; i ++ ) printf("%.2lf\n", a[i][n]);
        }
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    组合数

    在这里插入图片描述

    1. 递推就是Cba = Cba-1 + Cb-1a-1
    2. 预处理就是qmi (logN复杂度)结合模运算里面的逆元C^b^~a~ = a! / ((a-b)!*b!),提前将所有阶乘的逆元和阶乘的值算出来
    3. lucas定理证明我看了懵懵懂懂,记住结论就行

    AcWing 885. 求组合数 I

    #include 
    #include 
    #include 
    
    using namespace std;
    const int N = 2e3 + 10, mod = 1e9 + 7;
    int c[N][N];
    void init()
    {
        for (int i = 0; i < N; ++ i)
            for (int j = 0; j <= i; ++ j)
                if (j == 0) c[i][j] = 1;//i == j的情况可以通过前面处理好的递推出来
                else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    void solve()
    {
        int n;
        cin >> n;
        init();
        while (n -- )
        {
            int a, b;
            cin >> a >> b;
            cout << c[a][b] << endl;
        }
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    AcWing 886. 求组合数 II

    1. 运用组合数的定义,即最基本的运算公式。
    2. 基本运算公式中含有除法,我们想把除法变成乘法。
    3. 前面说了除法变乘法,本题正好有取模预算,取模运算下除法变乘法可以用欧拉函数扩展。
    4. 模又是质数,可以用费马定理,费马定理可以用快速幂将N优化为logN复杂度
    #include 
    #include 
    #include 
    
    using namespace std;
    typedef long long LL;
    const int N = 1e5 + 10, mod = 1e9 + 7;
    int fact[N];//fact[i]表示i的阶乘
    int infact[N];//infact[i]表示i阶乘的逆元,可以由infact[i - 1] * i的逆元获得
    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 solve()
    {
        int n;
        cin >> n;
        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;
        }
        while (n -- )
        {
            int a, b;
            cin >> a >> b;
            printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
        }
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    AcWing 887. 求组合数 III

    在这里插入图片描述

    #include 
    #include 
    #include 
    
    using namespace std;
    typedef long long LL;
    
    int qmi(int a, int k, int p)
    {
        LL res = 1;
        while (k)
        {
            if (k & 1) res = res * a % p;
            a = (LL)a * a % p;
            k >>= 1;
        }
        return res;
    }
    int C(LL a, LL b, int p)//好坑,a和b可能是LL
    {
        if (a < b) return 0;
        if (b > a - b) b = a - b; //Ca b = Ca a - b,可以自己举个例子
        int x = 1, y = 1;
        for (int i = 0; i < b; ++ i)//就是C^b^~a~ = a! / ((a-b)!*b!)
        {
            x = (LL)x * (a - i) % p;
            y = (LL)y * (i + 1) % p;
        }
        return (LL)x * qmi(y, p - 2, p) % p;//p一定为质数
    }
    
    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;
    }
    
    void solve()
    {
        int n;
        cin >> n;
        LL a, b;
        int p;
        while (n -- )
        {
            cin >> a >> b >> p;//好坑,a和b可能是LL
            cout << lucas(a, b, p) << endl;
        }    
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    AcWing 888. 求组合数 IV

    在这里插入图片描述

    #include 
    #include 
    #include 
    
    using namespace std;
    const int N = 5e3;
    int primes[N], cnt;
    int sum[N];
    bool st[N];
    void init(int a)//初始化获得1-a之间所有的质数,数论里面学过 a一定可以分解成质因数的乘积
    {
        for (int i = 2; i <= a; ++ i)
        {
            if (!st[i]) primes[cnt++] = i;
            for (int j = 0; primes[j] <= a / i; ++ j)
            {
                st[i * primes[j]] = true;
                if (i % primes[j] == 0) break;
            }       
        }
    }
    
    int get(int x, int p)//获得每个质因数的数量
    {
        int res = 0;
        while (x)
        {
            res += x / p;
            x /= p;
        }
        return res;
    }
    
    vector<int> mul(vector<int> a, int b) //高精度乘法
    {
        int t = 0;
        vector<int> C;
        for (int i = 0; i < a.size(); ++ i)
        {
            t += a[i] * b;
            C.push_back(t % 10);
            t /= 10;
        }
    
        while (t)
        {
            C.push_back(t % 10);
            t /= 10;
        }
    
        return C;
    }
    
    void solve()
    {
        int a, b;
        cin >> a >> b;
        init(a);   
        for (int i = 0; i < cnt; ++ i)//计算结果中的所有质因数的数量
            sum[i] = get(a, primes[i]) - get(a - b, primes[i]) - get(b, primes[i]);
        
    
        vector<int> res;
        res.push_back(1);
        for (int i = 0; i < cnt; ++ i)
            for (int j = 1; j <= sum[i]; ++ j)
                res = mul(res, primes[i]);
                
        for (int i = res.size() - 1; i >= 0; -- i) cout << res[i];
    }
    int32_t main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);
        int T = 1;
        //cin >> T;
        while (T --) solve();
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
  • 相关阅读:
    golang八股文整理(持续搬运)
    GoFrame v2.5 版本发布,企业级 Golang 开发框架
    HTTP协议【网络基础/应用层】
    本是同根生-双数据库集群keepalived virtual_route_id冲突导致连接故障
    COLE HERSEE 48408 工业4.0、制造业X和元宇宙
    蚁群算法
    k8s单master--测试环境集群搭建
    猿创征文|Cglib代理之代理类方法的动态传递
    武汉光华芯CJC5340 ADC 数字音频系统模拟数字转换器
    Java——二叉搜索树
  • 原文地址:https://blog.csdn.net/chirou_/article/details/132700059