写在开头: 读者们,俯听我一言:本篇文章全面的讲解了各个知识点,并且为每一个知识点提供了模板,只要掌握其中的要点,您轻松就能够获得省一。如果您在阅读过程中有任何疑问或者纰漏之处,请随时私信联系我,我的耐心答复必将令您满意🤩。
一、数论
1.判断质数
注意 i i i 的终止条件本来是 i < = s q r t ( n u m ) i<=sqrt(num) i<=sqrt(num),但是计算开方太慢了,所以用 i ∗ i < = n u m i * i<=num i∗i<=num,
但是 i ∗ i i*i i∗i容易爆int,所以最终改成 i < = n u m / i i <=num / i i<=num/i,后面的其他代码也会采用这种写法,希望不会搞晕。
public static boolean is_prime(int num) {
for (int i = 2; i <= num / i; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
2.最大公约数
public static int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
3.最小公倍数
a和b最小公倍数是 a ∗ b g c d ( a , b ) \frac{a*b}{gcd(a,b)} gcd(a,b)a∗b,由于a*b可能爆int,所以采用先除再乘, l c m ( a , b ) = a g c d ( a , b ) ∗ b lcm(a,b)=\frac{a}{gcd(a,b)}*b lcm(a,b)=gcd(a,b)a∗b
public static int lcm(int a, int b){
return a/gcd(a,b)*b;
}
public static int gcd(int a, int b) {
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
return a;
}
4.筛质数
下面的两种方法可以得到 小于等于n 的所有质数。
要想一次性得到很多质数,那么就要使用质数筛法,质数筛法有很多方法,现在给出一种 埃及筛法。这种方法写起来比较简单,而且比较快,强烈推荐这种写法。时间复杂度是: O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
public static void getPrimes(int n) {
boolean[] is_prime = new boolean[n + 1];
Arrays.fill(is_prime, true);
for (int i = 2; i <= n / i; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false;
}
}
}
for (int i = 2; i <= n ; i++) {
if (is_prime[i]){
System.out.println(i);
}
}
}
5.欧拉函数
欧拉函数:用于求小于等于n的数与n互质的个数是几个。
欧拉函数是积性函数,也就是 f ( a ∗ b ) = f ( a ) ∗ f ( b ) f(a*b)=f(a)*f(b) f(a∗b)=f(a)∗f(b)
public static int f(int n) {
int res = n;
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
res -= res / i;
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
res -= res / n;
}
return res;
}
6.区间欧拉函数
该代码用于求小于等于n的数,它们每一个欧拉函数值φ(n)。
此外,当n为质数时, φ ( n ) = n − 1 φ(n) = n-1 φ(n)=n−1
public static int[] oula(int n) {
int[] res = new int[n + 1];
for (int i = 0; i < res.length; i++) {
res[i] = i;
}
for (int i = 2; i <= n; i++) {
if (res[i] == i) {
for (int j = i; j <= n; j += i) {
res[j] -= res[j] / i;
}
}
}
return Arrays.copyOfRange(res, 1, n + 1);
}
7.计算所有约数个数
12的约数有:1,2,3,4,6,12
所以12的约数个数是6
public static int count(int n) {
public static long getSum(int n) {
long result = 0L;
for (int i = 1; i <= n / i; i++) {
if (n % i == 0) {
result++;
if (i * i != n) {
result ++;
}
}
}
return result;
}
}
8.计算所有约数和
12的约数有:1,2,3,4,6,12
所以12的约数个数是28
public static long getSum(int n) {
long result = 0L;
for (int i = 1; i <= n / i; i++) {
if (n % i == 0) {
result += i;
if (i * i != n) {
result += n / i;
}
}
}
return result;
}
9.计算质因子个数
12的约数有:1,2,3,4,6,12
所以12的质约数个数是2
public static void count(int n) {
int count = 0;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
count++;
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
count++;
}
System.out.println(count);
}
10.扩展欧几里得
扩展欧几里得:用途是求解 a x + b y = g c d ( a , b ) ax+by = gcd(a,b) ax+by=gcd(a,b) 中的 x 和 y x和y x和y 的值
已知,gcd(a,b) = d, 则存在 x,y 使得 a x + b y = d = g c d ( a , b ) ax+by = d = gcd(a,b) ax+by=d=gcd(a,b)
特别的,如果a,b互质,当且仅当 a x + b y = 1 ax+by=1 ax+by=1
如果 v % d = 0 v\%d=0 v%d=0,那么 a x + b y = v ax+by=v ax+by=v 的解是 a x + b y = d ax+by=d ax+by=d 的解的 v d \frac{v}{d} dv 倍数
public static int[] ex_gcd(int a, int b) {
if (b == 0) {
return new int[]{
a, 1, 0};
} else {
int[] result = ex_gcd(b, a % b);
return new int[]{
result[0], result[2], result[1] - (a / b) * result[2]};
}
}
12.快速幂
Java中有Biginteger类,可以实现该操作。
public static int quickPower(int a, int b) {
if (b == 1) return a;
int half = quickPower(a, b / 2);
if (b % 2 == 0) {
return half * half;
} else {
return half * half * a;
}
}
13.快速幂取模
Java可以用Biginteger类的power和mod方法,更方便。但是,这种思想也要掌握。
public static int quickPowerMod(int a, int b, int c) {
if (b == 1) return a;
int half = quickPowerMod(a, b / 2, c) % c;
if (b % 2 == 0) {
return half * half;
} else {
return half * half * a;
}
}
14.欧拉定理
用 φ ( n ) φ(n) φ(n) 表示n的欧拉函数值,那么:
欧拉定理:若a和n互质,则 a φ ( n ) = 1 ( m o d n ) a^{φ(n)}=1(mod\ n) aφ(n)=1(mod n)
费马定理:若a和n互质,并且n为质数,那么 φ(n) = n-1,此时 a n − 1 = 1 ( m o d n ) a^{n-1}=1(mod\ n) an−1=1(mod n)
根据上面的两个定理,我们可以得到 a关于n的逆元:
若a和n互质,则 a − 1 ( m o d n ) = a φ ( n ) − 1 a^{-1}(mod\ n)=a^{φ(n) -1} a−1(mod n)=aφ(n)−1
若a和n互质,并且n为质数,那么 φ(n) = n-1,此时 a − 1 ( m o d n ) = a n − 2 a^{-1}(mod\ n)=a^{n-2} a−1(mod n)=an−2
15.求a关于b的逆元
若a和n互质,则 a − 1 ( m o d n ) = a φ ( n ) − 1 a^{-1}(mod\ n)=a^{φ(n) -1} a−1(mod n)=aφ(n)−1
若a和n互质,并且n为质数,那么 a − 1 ( m o d n ) = a n − 2 a^{-1}(mod\ n)=a^{n-2} a−1(mod n)=an−2
使用快速幂
a − 1 = q u i c k P o w e r M o d ( a , n − 2 , n ) a^{-1}=quickPowerMod(a,n-2,n) a−1=quickPowerMod(a,n−2,n)
public static int quickPowerMod(int a, int b, int c) {
if (b == 1) return a;
int half = quickPowerMod(a, b / 2, c) % c;
if (b % 2 == 0) {
return half * half;
} else {
return half * half * a;
}
}
public static int f(int a, int b) {
return quickPowerMod(a, b-2, b);
}
16.中国剩余定理
中国剩余定理(Chinese Remainder Theorem,CRT)是解决一类同余方程组的经典方法,它可以在同余方程组中减少运算的数量,从而提高计算效率。其公式为:
x ≡ a i m o d m i , i = 1 , 2 , . . . , n x \equiv a_i \bmod m_i,\ i = 1,2,...,n x≡aimodmi, i=1,2,...,n
其中 m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn 两两互质, M = m 1 × m 2 × . . . × m n M = m_1 \times m_2 \times ... \times m_n M=m1×m2×...×mn, M i = M / m i M_i = M/m_i Mi=M/mi。则同余方程组的解为:
x ≡ ( ∑ i = 1 n a i M i x i ) m o d M x \equiv (\sum_{i=1}^{n} a_iM_ix_i) \bmod M x≡(i=1∑naiMixi)modM
其中 x i x_i xi 是 M i M_i Mi 在模 m i m_i mi 意义下的逆元,即 M i x i ≡ 1 m o d m i M_ix_i \equiv 1 \bmod m_i Mixi≡1modmi。
注意,当 m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn 不互质时,同余方程组中不一定存在解,此时需要进行合并或者降维(取模)等操作,转化为互质的情况,然后再使用CRT进行求解。
二、背包问题
1. 01 背包(采用状态压缩)
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int M = scanner.nextInt();
int N = scanner.nextInt();
int[] value = new int[N + 1];
int[] weight = new int[N + 1];
int[] dp = new int[M + 1];
for (int i = 1; i <= N; i++) {
weight[i] = scanner.nextInt();
value[i] = scanner.nextInt();
}
for (int i = 1; i <= N; i++) {
for (int j = M; j >= weight