必备模板
一、二分模板
1. 求最小值模板
牢记位运算和正常运算的转换:
x
>
>
y
=
⌊
x
2
y
⌋
x
<
<
y
=
2
y
x
x>>y=\lfloor \frac{x}{2y} \rfloor \\ x<<y=2yx
x>>y=⌊2yx⌋x<<y=2yx
表达式 | 值 |
---|---|
x >> y | ⌊ x 2 y ⌋ \lfloor \frac{x}{2y} \rfloor ⌊2yx⌋ |
x << y | 2 y x 2yx 2yx |
x & 1 | b ≡ 求这个值 ( m o d 2 ) b \equiv 求这个值 \pmod 2 b≡求这个值(mod2) |
while (l < r) {
int mid = l + (r - l >> 1); // int mid = (l + r) / 2;
if (check(mid))
r = mid;
else
l = mid + 1;
}
2. 求最大值模板
while (l < r) {
int mid = l + (r - l - 1 >> 1); // int mid = (l + r + 1) / 2
if (check(mid))
l = mid;
else
r = mid - 1;
}
二、数学
1. 运算
① 快速幂模板
原理:对于要求的
a
b
a^b
ab:
a
b
=
{
2
a
b
2
if
b
≡
1
(
m
o
d
2
)
a
×
2
a
⌊
b
2
⌋
if
b
≡
0
(
m
o
d
2
)
a^b = \begin{cases} 2a^{\frac{b}{2}} & \text{if } b \equiv 1 \pmod 2 \\ a\times2a^{\lfloor \frac{b}{2} \rfloor} & \text{if } b \equiv 0 \pmod 2 \end{cases}
ab={2a2ba×2a⌊2b⌋if b≡1(mod2)if b≡0(mod2)
int qpow(int a, int b) {
int ret = 1;
while (b) {
if (b & 1) // if (b % 2 == 1)
ret = (ret * a) % MOD;
a = (a * a) % MOD;
b >>= 1; // b /= 2
}
return ret;
}
② 最大公约数/最小公倍数
int gcd(int x, int y) {
return y ? gcd(y, x % y) : x;
}
int lcm(int x, int y) {
return x / gcd(x, y) * y; // 避免爆long long
}
③ 扩展欧几里得算法
概念:exgcd()
返回 gcd()
的返回结果,其中还可以求得两数
x
,
y
x,y
x,y 满足下面的条件:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
(
x
,
y
∈
Z
)
ax+by=gcd(a,b)(x,y\in \mathbb Z )
ax+by=gcd(a,b)(x,y∈Z)
int exgcd(int a, int b) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b), k = x;
x = y, y = k - a / b * y;
return d;
}
2. 素数
① 欧拉筛法
memset(isPrime, 1, sizeof(isPrime));
for (int i = 2; i <= n; i++) {
if (isPrime[i]) prime[pos++] = i; // 存入素数表
for (int j = 1; j <= pos-1 && i * prime[j] <= n; j++) { // 筛掉i所有素数倍的数,直到i的最小素因子倍位置
isPrime[i * prime[j]] = 0; // 标记为合数
if (i % isPrime[j] == 0) break; // 筛到最小素因子为止
}
}
② 判断素数
bool isPrime(int x) {
if (x <= 1) return false;
for (int i = 2; i * i <= x; i++)
if (x % i == 0)
return false;
return true;
}
③ 分解质因数
最常用写法:
for (int i = 2; i * i <= n; i++)
while (n % i == 0) {
printf("%d ", i);
n /= i;
}
if (n > 2) printf("%d", n);
大数据规模写法:
while (n % 2 == 0) rintf("2 ")
for (int i = 3; i * i <= n; i += 2)
while (n % i == 0) {
printf("%d ", i);
n /= i;
}
if (n > 2) printf("%d", n);
三、图论基础
1. 组合数
dp[1][1] = 1;
dp[2][1] = dp[2][2] = 1;
for (int i = 3; i <= n; i++)
for (int j = 1; j <= i; j++)
dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
2. Floyd-Warshall 算法(多源最短路)
for (int k = 1; k <= n; k++) // 中转站
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
if (dis[i][j] == INF || i == j) continue; // 可以降一点时间
dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j];
}