序列 DP

一般序列 DP 核心思想:将序列的前 \(i\) 个数的状态用一个更简单的形式表示出,并且体现出这些状态对后续的影响。

题目

ABC 267D

给定一个序列 \(a\),找到一个长度为 \(m\) 的子序列 \(b\),使得 \(\sum b_i × i\) 最大。

\(n, m \le 2 × 10^3\)。

状态:\(f(i, j)\):前 \(i\) 个数,选 \(j\) 个数的最大和;

转移:\(f(i, j) = \max(f(i - 1, j), f(i - 1, j - 1) + a_i \times j)\)。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 2010; int n, m;
ll a[N], dp[N][N]; int main() {
memset(dp, 128, sizeof dp);
n = read(), m = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read();
dp[i][0] = 0;
}
dp[0][0] = 0;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= min(i, m); ++ j) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] + 1ll * j * a[i]);
}
}
printf("%lld\n", dp[n][m]);
return 0;
}

B3637 最长上升子序列

给定一个序列,求它的最长上升子序列。\(n \le 5000\)

状态:\(dp_i\):最长上升子序列中第 \(i\) 个元素(是什么);

转移:如果 新元素 \(a\) 大于 \(dp_i\),则 \(dp_{i + 1} = a\),否则,二分出第一个大于等于 \(a\) 的前一个位置,替换上它。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} int n;
int y[100], dp[100]; int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
y[i] = read();
}
dp[1] = y[1];
int cnt = 1;
for (int i = 2; i <= n; ++ i) {
if (y[i] > dp[cnt]) {
dp[++ cnt] = y[i];
}
else {
int p = lower_bound(dp + 1, dp + cnt + 1, y[i]) - dp;
dp[p] = y[i];
}
}
printf("%d\n", cnt);
return 0;
}

P1439 【模板】最长公共子序列

给定两个 \(1, 2, 3 \cdots n\) 的序列 \(a, b\),求它们的最长公共子序列。

\(n \le 10^5\)。

  • 朴素做法 \(O_{n^2}\):

    状态:\(dp(i, j)\):第一个串的前 \(i\) 位,第二个串的前 \(j\) 位的 LCS 的长度;

    如果当前的 \(a_i = b_j\) 相同(即是有新的公共元素) 那么 dp[i][j]=max(dp[i][j],dp[i−1][j−1])+1;;如果不相同,即无法更新公共元素,考虑继承:dp[i][j]=max(dp[i−1][j],dp[i][j−1])
#include<iostream>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 2010; int n, m;
int dp[N][N], a1[N], a2[N]; int main() {
n = read(), m = read();
for (int i = 1; i <= n; ++ i) {
a1[i] = read();
}
for (int i = 1; i <= m; ++ i) {
a2[i] = read();
}
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if (a1[i] == a2[j]) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
}
printf("%d\n", dp[n][m]);
return 0;
}
  • 针对本题的 \(O_{n \log n}\) 做法。

    我们将 \(b\) 中的元素改为该元素在 \(a\) 中的位置,如果有一段位置是单调递增的,则这一段就是公共的子序列,我们再进行 DP。

    状态:\(dp_i\):最长公共子序列的第 \(i\) 个元素(是什么);

    转移:如果当前的 \(b_i\) 大于 \(dp_{last}\),则 \(dp_{last + 1} = b_i\),否则,二分找出大于等于 \(b_i\) 的前一个位置,替换。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int N = 1e5 + 5; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} int n;
ll a[N], b[N], l[N], dp[N]; int main() {
n = read();
for (int i = 1; i <= n; ++i) {
a[i] = read();
l[a[i]] = i;
}
for (int i = 1; i <= n; ++i) {
b[i] = read();
b[i] = l[b[i]];
}
int len = 1, s;
dp[1] = b[1];
for (int i = 2; i <= n; ++i) {
if (b[i] > dp[len]) {
len ++;
dp[len] = b[i];
}
else {
s = lower_bound(dp + 1, dp + len + 1, b[i]) - dp;
dp[s] = b[i];
}
}
printf("%d", len);
return 0;
}

区间 DP

区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来有很大的关系。

令状态 \(f(i,j)\) 表示将下标位置 \(i\) 到 \(j\) 的所有元素合并能获得的价值的最大值,那么 \(f(i,j)=\max\{f(i,k)+f(k+1,j)+cost\}\),\(cost\) 为将这两组元素合并起来的代价。

题目

P1775 石子合并

有 \(n\) 堆石子,每堆石子有编号有重量,现在要将它们合并成一堆,只能合并相邻的两堆石子,且代价为两堆石子的重量和,求最小代价。\(n \le 300\)

状态:\(dp(i, j)\):合并 \(\left[ i, j \right]\) 的石子的最小代价。

转移:\(dp(i, j) = \min_{k = i}^{j - 1} \left\{ dp(i, k) + dp(k + 1, j) + cost(i, j) \right\}\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 410; int n;
int a[N], dp[N][N], s[N]; int main() {
memset(dp, 0x3f, sizeof dp);
n = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read();
dp[i][i] = 0;
s[i] = s[i - 1] + a[i];
}
for (int l = 2; l <= n; ++ l) {
for (int i = 1; i + l - 1 <= n; ++ i) {
int j = i + l - 1;
for (int k = i; k < j; ++ k) {
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1]);
}
}
}
printf("%d\n", dp[1][n]);
return 0;
}

P4170 [CQOI2007]涂色

有一条长度为 \(5\) 的木板,初始时没有涂过任何颜色。每次你可以把一段连续的木板涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。用尽量少的涂色次数达到目标。\(n \le 50\)

状态:\(dp(i, j)\) 将木板 \(\left[ i, j \right]\) 涂成目标颜色的最小涂色次数。

转移:

如果 \(color_j = color_{j - 1}\),则 \(dp(i, j) = dp(i - 1, j)\);

否则 \(dp(i, j) = \min_{k = i}^{j - 1} \left \{ dp(i, k) + dp(k + 1, j) \right \}\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 100; int n;
char s[N];
ll dp[N][N]; int main() {
scanf("%s", s + 1);
n = strlen(s + 1);
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; ++ i)
dp[i][i] = 1;
for (int l = 1; l < n; ++ l) {
for (int i = 1; i + l <= n; ++ i) {
int j = i + l;
if (s[i] == s[j]) {
dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]);
} else {
for (int k = i; k < j; ++ k)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
}
}
}
printf("%lld\n", dp[1][n]);
return 0;
}

P1220 关路灯

在一条路线上安装了 \(n\) 盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。现在已知老张走的速度为 \(1m/s\),每个路灯的位置(是一个整数,即距路线起点的距离,单位:m)、功率(W),老张关灯所用的时间很短而可以忽略不计。问:怎样最省电?\(n \le 50\)

考虑对于状态的设计,关掉一段区间的灯,需要存下左右端点,需要两维,对于关掉区间 \(\left [ l, r \right ]\),最后一次只可能是关掉 \(l\) 位置的灯或者 \(r\) 位置的灯,即最后停留的位置有最左端与最右端两种,且对答案有影响,再加一维来存这两种情况。

状态:\(dp(i, j, 0/1)\)

转移:\(dp(i, j, 0) = \min(dp(i + 1, j, 0) + cost_1, dp(i + 1, j, 1) + cost_2\)),

\(dp(i, j, 1) = \min(dp(i, j - 1, 0) + cost_1, dp(i, j - 1, 1) + cost_2)\),

初始化:\(dp(c, c, 0) = 0, dp(c, c, 1) = 0\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int f = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
f |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return f ? ~x + 1 : x;
} const int N = 110; int n, c, sum, ans;
int a[N], w[N], s[N];
int dp[N][N][2];
bool b[N]; int main() {
n = read(), c = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read(), w[i] = read();
s[i] = s[i - 1] + w[i];
}
memset(dp, 0x3f, sizeof dp);
dp[c][c][0] = 0;
dp[c][c][1] = 0;
for (int j = c; j <= n; ++ j) {
for (int i = j - 1; i >= 1; -- i) {
dp[i][j][0] = min(dp[i + 1][j][0] + (a[i + 1] - a[i]) * (s[n] + s[i] - s[j]), dp[i + 1][j][1] + (a[j] - a[i]) * (s[n] + s[i] - s[j]));
dp[i][j][1] = min(dp[i][j - 1][0] + (a[j] - a[i]) * (s[n] + s[i - 1] - s[j - 1]), dp[i][j - 1][1] + (a[j] - a[j - 1]) * (s[n] + s[i - 1] - s[j - 1]));
}
}
ans = min(dp[1][n][0], dp[1][n][1]);
printf("%d", ans);
return 0;
}

P3146 [USACO16OPEN]248 G

给定一个 \(1 \times n\) 的地图,在里面玩 2048,每次可以合并相邻两个(数值范围 \(1 \sim 40\)),问序列中出现的最大数字的值最大是多少。注意合并后的数值并非加倍而是 \(+1\),例如 \(2\) 与 \(2\) 合并后的数值为 \(3\),\(2 \le n \le 248\)

这里要考虑 2048 的游戏规则,即只有两个相邻的数相等才能合。

状态:\(dp(i, j)\):合并区间 \(\left [ i, j \right ]\) 后的最大数值。

转移:\(dp(i, j) = \max(dp(i, j), dp(k + 1, j) + 1)\),条件:\(dp(i, k) = dp(k + 1, j)\),这里要注意,如果 \(dp(k + 1, j)\) 为 \(0\),说明这段区间没被更新到,因此答案也不可能为 \(1\),应该为 \(0\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 510; int n, ans;
int a[N];
int dp[N][N]; int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read();
dp[i][i] = a[i];
}
for (int len = 1; len <= n - 1; ++ len)
for (int i = 1; i <= n - len; ++ i) {
int j = i + len;
for (int k = i; k < j; ++ k) {
if (dp[k + 1][j] > 0 && dp[i][k] == dp[k + 1][j]) {
dp[i][j] = max(dp[i][j], dp[k + 1][j] + 1);
ans = max(ans, dp[k + 1][j] + 1);
}
}
}
printf("%d", ans);
return 0;
}

P3205 [HNOI2010]合唱队

合唱队一共 \(n\) 个人,第 \(i\) 个人的身高为 \(h_i\) 米(\(1000 \le h_i \le 2000\)),并已知任何两个人的身高都不同。假定最终排出的队形是 \(A\) 个人站成一排,为了简化问题,小 A 想出了如下排队的方式:他让所有的人先按任意顺序站成一个初始队形,然后从左到右按以下原则依次将每个人插入最终棑排出的队形中: 第一个人直接插入空的当前队形中;对从第二个人开始的每个人,如果他比前面那个人高(\(h\) 较大),那么将他插入当前队形的最右边。如果他比前面那个人矮(\(h\) 较小),那么将他插入当前队形的最左边。当 \(n\) 个人全部插入当前队形后便获得最终排出的队形。答案要对 \(19650827\) 取模,\(n \le 1000\),\(1000 \le h_i \le 2000\)。

这道题与关路灯那道题差不多,在状态设计上要考虑上一个被插入的人是插入的左边还是右边。

状态:\(dp(i, j, 0/1)\):区间 \(\left[ i, j \right]\) 中,最后一个人被插入了 \(0\) 左边 / \(1\) 右边。

转移:

如果 \(a_i < a_j\),那么 \(dp(i, j, 0) = dp(i, j, 0) + dp(i + 1, j, 1), dp(i, j, 1) = dp(i, j, 1) + dp(i, j - 1, 0)\),

如果 \(a_i < a_{i + 1}\),那么 \(dp(i, j, 0) = dp(i, j, 0) + dp(i + 1, j, 0)\),

如果 \(a_j > a_{j - 1}\),那么 \(dp(i, j, 1) = dp(i, j, 1) + dp(i, j - 1, 1)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} const int N = 2010;
const int mod = 19650827; int dp[N][N][2], a[N]; int main() {
int n;
n = read();
for (int i = 1; i <= n; ++ i)
a[i] = read();
for (int i = 1; i <= n; ++ i)
dp[i][i][0] = 1;
for (int i = n - 1; i >= 1; -- i) {
for (int j = i + 1; j <= n; ++ j) {
if (a[i] < a[j]) {
dp[i][j][0] += dp[i + 1][j][1];
dp[i][j][1] += dp[i][j - 1][0];
dp[i][j][0] %= mod;
dp[i][j][1] %= mod;
}
if (a[i] < a[i + 1]) {
dp[i][j][0] += dp[i + 1][j][0];
dp[i][j][0] %= mod;
}
if (a[j] > a[j - 1]) {
dp[i][j][1] += dp[i][j - 1][1];
dp[i][j][1] %= mod;
}
}
}
printf("%d", (dp[1][n][0] + dp[1][n][1]) % mod);
return 0;
}

环状 DP

在环上的 DP,基本方法就是断环为链,然后把它作为区间 DP 或 序列 DP 去做。作为区间 DP 做时有一个小技巧就是将 这个链复制两遍,以防止首位的一些非法情况被我们计算。

P1880 [NOI1995] 石子合并

石子合并,但是,是在环上。\(n \le 100\)

断环为链,复制两遍这条链转化为区间 DP。

状态:\(f1(i, j)\):区间 \(\left[ i, j \right ]\) 的最大得分,\(f2(i, j)\):区间 \(\left[ i, j \right ]\) 的最小得分。

转移:\(f1(i, j) = \max_{k = i}^{j - 1}\{f1(i, j), f1(i, k) + f1(k + 1, j) + cost\}\)

\(f2(i, j) = \min_{k = i}^{j - 1}\{f2(i, j), f2(i, k) + f2(k + 1, j) + cost\}\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} ll r[600], g[600];
ll f1[600][600], f2[600][600]; int main() {
int n;
n = read();
for (int i = 1; i <= n; ++i) {
r[i] = read();
r[i + n] = r[i];
g[i] = g[i - 1] + r[i];
f1[i][i] = f2[i][i] = 0;
}
for (int i = n + 1; i <= 2 * n; ++i) {
f2[i][i] = 0;
g[i] = g[i - 1] + r[i];
}
for (int l = 1; l < n; ++l) {
for (int i = 1, j = i + l; i < n * 2 && j <= n * 2; ++i, j = i + l) {
f2[i][j] = 100000000;
for (int k = i; k < j; ++k) {
f1[i][j] = max(f1[i][j], f1[i][k] + f1[k + 1][j] + g[j] - g[i - 1]);
f2[i][j] = min(f2[i][j], f2[i][k] + f2[k + 1][j] + g[j] - g[i - 1]);
}
}
}
ll maxn = 0, minn = 1e18;
for (int i = 1; i <= n; ++i) {
maxn = max(maxn, f1[i][i + n - 1]);
minn = min(minn, f2[i][i + n - 1]);
}
printf("%lld\n%lld", minn, maxn);
return 0;
}

P1063 [NOIP2006 提高组] 能量项链

给定一个有 \(n\) 个珠子的项链,每个珠子有头标记和尾标记,相邻两个珠子,前一个珠子的尾标记等于后一个珠子的头标记,只有相邻的两个柱子能合并成一个,并产生能量,能量为 \(前一颗珠子的头标记 \times 后一颗珠子的头标记 \times 后一颗珠子的尾标记\),合并后的新珠子,头标记等于前一颗珠子的头标记,尾标记等于后一颗珠子的尾标记。求最大能量。\(4 \le n \le 400\)

很经典的环形 DP 题。

状态:\(dp(i, j)\): 合并区间 \(\left[ i, j \right]\) 释放的最大能量。

转移:\(dp(i, j) = \max_{k = i}^{j - 1}\{dp(i, k) + dp(k + 1, j) + a_i \times a_{k + 1} \times a_{j + 1} \}\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
int fg = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
fg |= (ch == '-');
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return fg ? ~x + 1 : x;
} int n;
ll a[300], f[300][300];
ll maxn; int main() {
n = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read();
a[i + n] = a[i];
}
for (int i = 2; i < 2 * n; ++ i)
for (int j = i - 1; i - j < n && j >= 1; -- j)
for (int k = j; k < i; ++ k) {
f[j][i] = max(f[j][i], a[j] * a[k + 1] * a[i + 1] + f[j][k] + f[k + 1][i]);
if (f[j][i] > maxn) maxn = f[j][i];
}
printf("%lld", maxn);
return 0;
}

「学习笔记」DP 学习笔记1的更多相关文章

  1. 「刷题笔记」DP优化-状压-EX

    棋盘 需要注意的几点: 题面编号都是从0开始的,所以第1行实际指的是中间那行 对\(2^{32}\)取模,其实就是\(unsigned\ int\),直接自然溢出啥事没有 棋子攻击范围不会旋转 首先, ...

  2. 「LibreOJ#516」DP 一般看规律

    首先对于序列上一点,它对答案的贡献只有与它的前驱和后驱(前提颜色相同)构成的点对, 于是想到用set维护每个颜色,修改操作就是将2个set暴力合并(小的向大的合并),每次插入时更新答案即可 颜色数要离 ...

  3. 「学习笔记」平衡树基础:Splay 和 Treap

    「学习笔记」平衡树基础:Splay 和 Treap 点击查看目录 目录 「学习笔记」平衡树基础:Splay 和 Treap 知识点 平衡树概述 Splay 旋转操作 Splay 操作 插入 \(x\) ...

  4. 「学习笔记」Min25筛

    「学习笔记」Min25筛 前言 周指导今天模拟赛五分钟秒第一题,十分钟说第二题是 \(\text{Min25}​\) 筛板子题,要不是第三题出题人数据范围给错了,周指导十五分钟就 \(\text{AK ...

  5. 「学习笔记」FFT 之优化——NTT

    目录 「学习笔记」FFT 之优化--NTT 前言 引入 快速数论变换--NTT 一些引申问题及解决方法 三模数 NTT 拆系数 FFT (MTT) 「学习笔记」FFT 之优化--NTT 前言 \(NT ...

  6. 「学习笔记」FFT 快速傅里叶变换

    目录 「学习笔记」FFT 快速傅里叶变换 啥是 FFT 呀?它可以干什么? 必备芝士 点值表示 复数 傅立叶正变换 傅里叶逆变换 FFT 的代码实现 还会有的 NTT 和三模数 NTT... 「学习笔 ...

  7. 「学习笔记」Treap

    「学习笔记」Treap 前言 什么是 Treap ? 二叉搜索树 (Binary Search Tree/Binary Sort Tree/BST) 基础定义 查找元素 插入元素 删除元素 查找后继 ...

  8. 「学习笔记」字符串基础:Hash,KMP与Trie

    「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...

  9. Note -「Lagrange 插值」学习笔记

    目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...

  10. Note -「单位根反演」学习笔记

    \(\mathcal{Preface}\)   单位根反演,顾名思义就是用单位根变换一类式子的形式.有关单位根的基本概念可见我的这篇博客. \(\mathcal{Formula}\)   单位根反演的 ...

随机推荐

  1. LeetCode 周赛 338,贪心 / 埃氏筛 / 欧氏线性筛 / 前缀和 / 二分查找 / 拓扑排序

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 上周末是 LeetCode 第 338 场周赛,你参加了吗?这场周赛覆盖的知识点很多,第 ...

  2. STM32F407 学习 (0) 各种外设功能 (上)

      本文对正点原子STM32F4探索者的基本功能及外设作最基本的介绍,随笔者本人的学习进程(基本按照正点原子)而不定时更新,起到总结的作用. 一.HAL库编写程序的运行逻辑   HAL库函数(如stm ...

  3. DataLeap 数据资产实战:如何实现存储优化?

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 背景 DataLeap 作为一站式数据中台套件,汇集了字节内部多年积累的数据集成.开发.运维.治理.资产.安全等全 ...

  4. MySQL--索引的数据结构

    1.为什么使用索引 索引是存储引擎用于快速找到数据记录的一种数据结构,就好比一本教科书的目录部分,通过目录中找到对应文章的页面,便可以快速定位到需要的文章,mysql中也是一样的道理,进行数据查找时, ...

  5. [SVN]SVN checkout 功能不可用 右键只看到提交和更新,没有显示checkout[转载]

    不要在受SVN控制的文件夹里点右键,因为这个文件夹已经在SVN控制之下,当然不会允许在里面嵌套另一个SVN版本库 换个不受控的文件夹点右键,比如: D盘根目录 X 参考文献 SVN checkout ...

  6. 好奇心驱使下试验了 chatGPT 的 js 代码的能力

    手边的项目中有个函数,主要实现图片分片裁剪功能.可以优化一下. 也想看看 chatGPT 的代码理解能力,优化能力,实现能力,用例能力. 于是有了这篇文章. 实验结果总结: chatGPT 确实强大, ...

  7. C++ sizeof与strlen,并借此明晰内存对齐

    前言 sizeof()与strlen()都是为了获取对象的长度.在正常编写C++的算法程序代码时,可能这两个都很少用到,因为各种stl容器的封装已经给了我们很大的便利,比如我们在想要获取自定义的vec ...

  8. Zabbix - 部署随笔

    部署Zabbix服务端 准备机器,初始化环境 #查看IP地址 [root@Minimal ~]# ifconfig ens33 | awk 'NR==2{print $2}' 10.0.0.243 # ...

  9. Springboot整合Flowable6.x导出bpmn20

    项目源码仓库 BPMN2.0(Business Process Model and Notation)是一套业务流程模型与符号建模标准,以XML为载体,以符号可视化业务,支持精准的执行语义来描述元素的 ...

  10. ShardingJDBC配置

    Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务. 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容J ...