1.高斯消元
(1)高斯消元解线性方程组
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)高斯消元解异或线性方程组
异或:不进位的加法
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);
}
}