2024-02-03(高斯消元,求组合数)

1.高斯消元

(1)高斯消元解线性方程组 

883. 高斯消元解线性方程组 - AcWing题库

import java.io.*;

public class Main{
    static int N = 110, n;
    static double min = 1e-6;
    static double[][] a = new double[N][N];
    
    public static void swap(int x1, int y1, int x2, int y2){
        double temp = a[x1][y1];
        a[x1][y1] = a[x2][y2];
        a[x2][y2] = temp;
    }
    
    public static int guass(){
        int r, c;
        for(r = 0, c = 0; c < n; c ++){
            
            //找到未处理行中未处理列的绝对值中最大的一行
            int t = r;
            for(int i = r; i < n; i ++){
                if(Math.abs(a[i][c]) > Math.abs(a[t][c])) t = i;
            }
            
            //如果最大值为0,那么就结束这次循环
            if(Math.abs(a[t][c]) < min) continue;
            
            //把绝对值最大的这一行换到所有未处理行的第一行
            for(int i = c; i <= n; i ++){
                swap(t, i, 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(Math.abs(a[i][c]) < min) continue;
                for(int j = n; j >= c; j --){
                    a[i][j] -= a[r][j] * a[i][c];
                }
            }
            r ++;
        }
        
        if(r < n){
            for(int i = r; i < n; i ++){
                if(Math.abs(a[i][n]) > min) return 2;
            }
            return 1;
        }
        for(int i = n - 1; i >= 0; i --){
            for(int j = i + 1; j < n; j ++){
                a[i][n] -= a[i][j] * a[j][n];
            }
        }
        return 0;
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        
        for(int i = 0; i < n; i ++){
            String[] str = br.readLine().split(" ");
            for(int j = 0; j < n + 1; j ++){
                a[i][j] = Double.parseDouble(str[j]);
            }
        }
        
        int t = guass();
        
        if(t == 2){
            System.out.print("No solution");
        }else if(t == 0){
            for(int i = 0; i < n; i ++){
                System.out.printf("%.2f\n", a[i][n]);
            }
        }else{
            System.out.print("Infinite group solutions");
        }
    }
}

(2)高斯消元解异或线性方程组 

884. 高斯消元解异或线性方程组 - AcWing题库

异或:不进位的加法 

 

import java.io.*;

public class Main{
    static int N = 110;
    static int[][] a = new int[N][N];
    static int n;
    
    public static void swap(int x1, int y1, int x2, int y2){
        int temp = a[x2][y2];
        a[x2][y2] = a[x1][y1];
        a[x1][y1] = temp;
    }
    
    //高斯消元
    public static int guass(){
        int r, c;
        for(r = 0, c = 0; c < n; c ++){
            int t = r;
            for(int i = t; i < n; i ++){
                if(a[i][c] == 1) t = i;
            }
            
            if(a[t][c] == 0) continue;
            
            for(int i = c; i < n + 1; i ++){
                swap(t, i, r, i);
            }
            
            for(int i = r + 1; i < n; i ++){
                if(a[i][c] == 0) continue;
                for(int j = c; j < n + 1; j ++){
                    a[i][j] ^= a[r][j];
                }
            }
            r ++;
        }
        
        if(r < n){
            for(int i = r; i < n; i ++){
                if(a[i][n] == 1) return 2;
            }
            return 1;
        }
        for(int i = n - 1; i >= 0; i --){
            for(int j = i + 1; j < n; j ++){
                a[i][n] ^= a[i][j] * a[j][n];
            }
        }
        return 0;
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        
        for(int i = 0; i < n; i ++){
            String[] str = br.readLine().split(" ");
            for(int j = 0; j < n + 1; j ++){
                a[i][j] = Integer.parseInt(str[j]);
            }
        }
        
        int res = guass();
        if(res == 0){
            for(int i = 0; i < n; i ++){
                System.out.println(a[i][n]);
            }
        }else if( res == 1){
            System.out.print("Multiple sets of solutions");
        }else System.out.print("No solution");
    }
}

 

2.求组合数

885. 求组合数 I - AcWing题库 (递推)

import java.util.*;

public class Main{
    static int N = 2010;
    static int[][] c = new int[N][N];
    static double mod = 1e9 + 7;
    
    public static void init(){
        for(int i = 0; i <= 2000; i ++){
            for(int j = 0; j <= i; j ++){
                if(j == 0) c[i][j] = 1;
                else c[i][j] = (int)((long)(c[i - 1][j] + c[i - 1][j - 1]) % mod);
            }
        }
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        init();
        while(n -- > 0){
            int a = sc.nextInt();
            int b = sc.nextInt();
            System.out.println(c[a][b]);
        }
    }
}

 886. 求组合数 II - AcWing题库  (快速幂求逆元)

AcWing 886. 关于求组合数 II的一些疑问 - AcWing

import java.io.*;

public class Main{
    static int N = 100010, mod = 1000000007;
    static long[] fact = new long[N];//阶乘
    static long[] infact = new long[N];//存逆元
    
    //快速幂求逆元
    public static long quick(long a, int k, int p){
        long res = 1;
        while(k != 0){
            if((k & 1) == 1) res = res * a % p;
            k >>= 1;
            a = a * a % p;
        }
        return res;
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        infact[0] = 1;
        fact[0] = 1;
        
        for(int i = 1; i < N; i ++){
            fact[i] = fact[i - 1] * i % mod;
            infact[i] = infact[i - 1] * quick(i, mod - 2, mod) % mod;
        }
        
        int n = Integer.parseInt(br.readLine());
        while(n -- > 0){
            String[] str = br.readLine().split(" ");
            int a = Integer.parseInt(str[0]);
            int b = Integer.parseInt(str[1]);
            long res = fact[a] * infact[b] % mod * infact[a - b] % mod;//由公式推导而来
            System.out.println(res);
        }
    }
}

887. 求组合数 III - AcWing题库 (卢卡斯定理)

import java.io.*;

public class Main{
    static int p;
    
    //快速幂求逆元
    static int quick(int a, int k){
        int res = 1;
        while(k != 0){
            if((k & 1) == 1) res = (int)((long)res * a % p);
            k >>= 1;
            a = (int)((long)a * a % p);
        }
        return res;
    }
    
    //定义法
    static int C(long a, long b){
        int res = 1;
        for(int i = 1, j = (int)a; i <= b; i ++, j --){
            res = (int)((long)res * j % p);
            res = (int)((long)res * quick(i, p - 2) % p);
        }
        return res;
    }
    
    //卢卡斯定理
    static int lucas(long a, long b){
        if(a < p && b < p){//如果a,b都小于p,那用定义法来求
            return C(a, b);
        }
        //否则用卢卡斯定理的公式来求
        return (int)((long)lucas(a / p, b / p) * C(a % p, b % p) % p);
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        int n = Integer.parseInt(br.readLine());
        while(n -- > 0){
            String[] str = br.readLine().split(" ");
            long a = Long.parseLong(str[0]);//一定要注意这些类型,要统一!!
            long b = Long.parseLong(str[1]);
            p = Integer.parseInt(str[2]);//最开始已经定义过了,一定不能重复定义!!!
            
            System.out.println(lucas(a, b));
        }
    }
}

888. 求组合数 IV - AcWing题库

import java.io.*;
import java.util.*;
import java.math.BigInteger;

public class Main{
    static int N = 100010, cnt;
    static int[] pr = new int[N];
    static int[] sum = new int[N];
    static boolean[] st = new boolean[N];
    
    
    //线性筛质数
    public static void get_primes(int n){
        for(int i = 2; i <= n; i ++){
            if(!st[i]) pr[cnt ++] = i;
            for(int j = 0; pr[j] <= n / i; j ++){
                st[pr[j] * i] = true;
                if(i % pr[j] == 0) break;
            }
        }
    }
    
    //n的阶乘中p的个数
    public static int get(int n, int p){
        int res = 0;
        while(n != 0){
            res += n / p;
            n /= p;
        }
        return res;
    }
    
    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] str = br.readLine().split(" ");
        int a = Integer.parseInt(str[0]);
        int b = Integer.parseInt(str[1]);
        
        get_primes(a);
        
        for(int i = 0; i < cnt; i ++){
            int p = pr[i];
            sum[i] = get(a, p) - get(b, p) - get(a - b, p);
        }
        
        BigInteger res = new BigInteger("1");
        
        for(int i = 0; i < cnt; i ++){
            int p = pr[i];
            for(int j = 0; j < sum[i]; j ++){
                res = res.multiply(new BigInteger(String.valueOf(p)));
            }
        }
        System.out.print(res);
    }
}

889. 满足条件的01序列 - AcWing题库(卡特兰数)

这种思想很重要!!! 

还有就是质数才能用快速幂求逆元,非质数要用扩展欧几里得算法来求

import java.util.*;

public class Main{
    static int mod = (int)1e9 + 7;
    
    public static long quick(long a, int k, int p){
        long res = 1;
        while(k != 0){
            if((k & 1) == 1) res = res * a % p;
            k >>= 1;
            a = a * a % p;
        }
        return res;
    }
    
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        long res = 1;
        for(int i = 2 * n; i > n; i --) res = res * i % mod;//求阶乘
        for(int i = 1; i <= n; i ++) res = res * quick(i, mod - 2, mod) % mod;//求逆元
        //最后乘上n+1的逆元
        res = res * quick(n + 1, mod - 2, mod) % mod;
        System.out.print(res);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值