写在前面

19 年前听 zlq 讲课的时候学的东西,当时只会抄板子,现在来重学一波= =

一个板子水一天题(不事

引入

「SCOI2009」Windy 数

给定参数 \(l,r\),求 \([l,r]\) 中不含前导零且相邻两个数字之差至少为 \(2\) 的正整数的个数。

\(1\le l\le r\le 2\times 10^9\)。

1S,512MB。

这是一个经典的数位 DP 的例子。其模型一般是给定一些对于数的限制条件,求在给定范围内满足限制的数的贡献。

通过数位 DP 一般可以在 \(O(m\log_{10}{(n)})\) 的时间内解决此问题,其中 \(m\) 是数码种类数,\(n\) 是取值的最大值。

求解

首先将询问 \([l,r]\) 内合法的数的个数拆成询问 \([0\sim l-1]\) 和 \([0, r]\) 内合法的数的个数,之后考虑数位 DP。

数位 DP 有递推 和 记忆化搜索两种写法,由于记忆化搜索更容易理解与实现,我们一般采用记忆化搜索解决此类问题。以下也仅介绍记忆化搜索的解法。

先考虑爆搜。考虑枚举所有范围内的数,搜索的同时检查是否满足给定的限制条件。注意考虑前导零与是否达到枚举的上界,其代码如下所示:

int numlth, num[kN]; //储存给定值的从高位到低位的十进制拆分。
//now_:当前填到第几位; last_:now_ - 1 位填的数;
//zero_:前 now_ - 1 位是否均为 0; lim_:前 now_ - 1 位是否达到枚举的上界(与 num 相同)
int Dfs(int now_, int last_, bool zero_, bool lim_) {
if (now_ > numlth) return 1; //当前枚举的数合法
int ret = 0;
//枚举第 now_ 位填的数,up 为该位填数的上界
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (abs(i - last_) < 2) continue ;
if (zero_ && !i) ret += Dfs(now_ + 1, 11, true, lim_ && i == up); //前 now_ 位均为 0
else ret += Dfs(now_ + 1, i, false, lim_ &&i == up);
}
return ret;
}
//ans[0, x] = Dfs(1, 11, true, true);

发现当枚举的数前缀的性质相同,即 dfs 的四个参数相同时,dfs 的返回值相同。

比如当枚举到 \(020\underline{?}??\) 和 \(010\underline{?}??\) 时,dfs 的参数均为 (4, 0, false, false)。表示它们前缀的性质相同,枚举之后位数得到的答案显然也相同。

简单记忆化即可避免重复枚举过程。

//f[i][j][0/1][0/1] 表示 dfs(i, j, 0/1, 0/1) 的答案。
int numlth, num[kN], f[kN][kN][2][2];
int Dfs(int now_, int last_, bool zero_, bool lim_) {
if (now_ > numlth) return 1;
if (f[now_][last_][zero_][lim_] != -1) return f[now_][last_][zero_][lim_];
int ret = 0;
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (abs(i - last_) < 2) continue ;
if (zero_ && !i) ret += Dfs(now_ + 1, 11, true, lim_ && i == up);
else ret += Dfs(now_ + 1, i, false, lim_ && i == up);
}
return f[now_][last_][zero_][lim_] = ret;
}
//ans[0, x] = Dfs(1, 11, true, true);

特判优化

发现上述 dfs 的过程中,\(\operatorname{lim} = 1\) 或 \(\operatorname{zero} = 1\) 的状态只会被枚举到 1 次,即只会重复调用 dfs(now_, last_, 0, 0)。对这两维的记忆化对减少枚举次数是做负功的。

于是可以通过特判去除这两维,如下所示:

//f[i][j] 表示 dfs(i, j, 0, 0) 的答案。
int Dfs(int now_, int last_, bool zero_, bool lim_) {
if (now_ > numlth) return 1;
if (!lim_ && f[now_][last_] != -1) return f[now_][last_];
int ret = 0;
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (abs(i - last_) < 2) continue ;
if (zero_ && !i) ret += Dfs(now_ + 1, 11, true, lim_ && i == up);
else ret += Dfs(now_ + 1, i, false, lim_ && i == up);
}
if (!lim_) f[now_][last_] = ret;
return ret;
}

可以感性理解特判的实际意义。若 dfs 的参数 \(\operatorname{lim} = 0\) 时,表示前缀比上界小,后面的位数可以随意填。因此前缀性质相同的所有子问题是完全等价的,因此可以记忆化。

\(\operatorname{zero} = 1\) 与 \(\operatorname{lim} = 0\) 一定是配套出现的,因此也可以特判掉。

这样时空复杂度均变为了原来的 \(\frac{1}{4}\)。在其他题目中也可以套用此模板,将 0/1 维特判掉,减小时空复杂度。

可能有___出题人卡直接记忆化的写法,比如这题:

代码

引入问题的完整代码。

//知识点:数位 DP
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <vector>
#define LL long long
const int kN = 15;
//=============================================================
int numlth, f[kN][kN];
std::vector <int> num;
//=============================================================
inline int read() {
int f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Chkmax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void Chkmin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
int Dfs(int now_, int last_, bool zero_, bool lim_) {
if (now_ > numlth) return 1;
if (!lim_ && f[now_][last_] != -1) return f[now_][last_];
int ret = 0;
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (abs(i - last_) < 2) continue ;
if (zero_ && !i) ret += Dfs(now_ + 1, 11, true, lim_ && i == up);
else ret += Dfs(now_ + 1, i, false, lim_ && i == up);
}
if (!lim_) f[now_][last_] = ret;
return ret;
}
int Calc(int val_) {
num.clear();
num.push_back(0);
for (int tmp = val_; tmp; tmp /= 10) num.push_back(tmp % 10);
for (int i = 1, j = num.size() - 1; i < j; ++ i, -- j) {
std::swap(num[i], num[j]);
}
numlth = num.size() - 1;
memset(f, -1, sizeof (f));
return Dfs(1, 11, true, true);
}
//=============================================================
int main() {
int a = read(), b = read();
printf("%d\n", Calc(b) - Calc(a - 1));
return 0;
}

例题

「ZJOI2010」数字计数

给定两个正整数 \(a\) 和 \(b\),求在 \([a,b]\) 中的所有整数中,每个数码各出现了多少次。

\(1\le a\le b\le 10^{12}\)。

1S,512MB。

与引入问题不同的是,这题要求的是数码的数量,限制了每个数的贡献,求贡献和。

套路类似,考虑对每个数码分开求解,dfs 时记录已枚举前缀的贡献量。

Dfs(int now_, LL sum_, bool zero_, bool lim_, int digit_) 表示前 \(\operatorname{now} - 1\) 位含有数码 \(\operatorname{digit}\) 的数量为 \(\operatorname{sum}\)、前缀是否全为前导零、前缀是否达到上界,满足上述条件的所有数中数码 \(\operatorname{digit}\) 的数量。

边界是搜索到第 \(\operatorname{length}+1\) 位,此时返回 \(\operatorname{sum}\) 的值。

与套路类似地,发现一些 \(\operatorname{now}\) 和 \(\operatorname{sum}\) 相等的搜索状态会被重复访问,简单记忆化即可。

总复杂度 \(O(10^2\log_{10}(n))\) 级别。

//知识点:数位 DP
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <vector>
#define LL long long
const int kN = 20;
//=============================================================
LL numlth, f[kN][kN];
std::vector <int> num;
//=============================================================
inline LL read() {
LL f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Chkmax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void Chkmin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
LL Dfs(int now_, LL sum_, bool zero_, bool lim_, int digit_) {
if (now_ > numlth) return sum_;
if (!lim_ && f[now_][sum_] != -1) return f[now_][sum_];
LL ret = 0;
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (zero_ && !i) ret += Dfs(now_ + 1, sum_, true, lim_ && i == up, digit_);
else ret += Dfs(now_ + 1, sum_ + (i == digit_), false, lim_ && i == up, digit_);
}
if (!lim_) f[now_][sum_] = ret;
return ret;
}
LL Calc(LL val_, int digit_) {
num.clear();
num.push_back(0);
for (LL tmp = val_; tmp; tmp /= 10) num.push_back(tmp % 10);
for (int i = 1, j = num.size() - 1; i < j; ++ i, -- j) std::swap(num[i], num[j]);
numlth = num.size() - 1;
memset(f, -1, sizeof (f));
return Dfs(1, 0, true, true, digit_);
}
//=============================================================
int main() {
LL a = read(), b = read();
for (int i = 0; i <= 9; ++ i) printf("%lld ", Calc(b, i) - Calc(a - 1, i));
return 0;
}

还有一种考虑每个位置填入指定数码后对应的数的个数的无脑写法,看代码就能看懂。

//知识点:暴力
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#define LL long long
const int kN = 13;
//=============================================================
LL f[kN];
//=============================================================
inline LL read() {
LL f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Chkmax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void Chkmin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
LL Calc(LL val_, LL digit_) {
LL ret = (!digit_);
for (LL tmp = val_, pow10 = 1; tmp; tmp /= 10ll, pow10 *= 10ll) {
LL pre = tmp / 10ll + 1;
if (! digit_) {
if (pre == 1) continue;
if (0 < tmp % 10) ret += (pre - 1ll) * pow10;
if (0 == tmp % 10) ret += (pre - 2ll) * pow10 + val_ % pow10 + 1;
continue;
}
if (digit_ > tmp % 10) ret += (pre - 1ll) * pow10;
if (digit_ == tmp % 10) ret += (pre - 1ll) * pow10 + val_ % pow10 + 1;
if (digit_ < tmp % 10) ret += pre * pow10;
}
return ret;
}
//=============================================================
int main() {
LL a = read(), b = read();
for (int i = 0; i <= 9; ++ i) printf("%lld ", Calc(b, i) - Calc(a - 1, i));
return 0;
}

「AHOI2009」同类分布

给定两个正整数 \(a\) 和 \(b\),求在 \([a,b]\) 中的所有整数中,各位数之和能整除原数的数的个数。

\(1\le a\le b\le 10^{18}\)。

3S,512MB。

考虑到各位数之和与原数在 dfs 中都是变量,不易检验合法性。但发现各位数之和不大于 \(9\times 12\),考虑先枚举各位数之和,再在 dfs 时维护前缀的余数,以检查是否合法。

同样设 Dfs(int now_, int sum_, int p_, bool zero_, bool lim_, int val_),其中 \(\operatorname{sum}\) 为前缀的各数位之和,\(p\) 为原数模 \(\operatorname{val}\) 的余数。

边界是搜索到第 \(\operatorname{length}+1\) 位,此时返回 \([\operatorname{sum}=\operatorname{val} \land \, p = 0]\)。

对数位和和余数简单记忆化即可,总复杂度 \(O(2\cdot10^2\log_{10}^3(n))\) 级别。

//知识点:数位 DP
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <vector>
#define LL long long
const int kN = 20;
//=============================================================
int numlth;
LL f[kN][9 * kN][9 * kN];
std::vector <int> num;
//=============================================================
inline LL read() {
LL f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Chkmax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void Chkmin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
LL Dfs(int now_, int sum_, int p_, bool zero_, bool lim_, int val_) {
if (now_ > numlth) return (sum_ == val_ && !p_);
if (!lim_ && f[now_][sum_][p_] != -1) return f[now_][sum_][p_];
LL ret = 0;
for (int i = 0, up = lim_ ? num[now_] : 9; i <= up; ++ i) {
if (zero_ && !i) ret += Dfs(now_ + 1, sum_, 10 * p_ % val_, true, lim_ && i == up, val_);
else ret += Dfs(now_ + 1, sum_ + i, (10 * p_ + i) % val_, false, lim_ && i == up, val_);
}
if (!zero_ && !lim_) f[now_][sum_][p_] = ret;
return ret;
}
LL Calc(LL val_) {
num.clear();
num.push_back(0);
for (LL tmp = val_; tmp; tmp /= 10) num.push_back(tmp % 10);
for (int i = 1, j = numlth = num.size() - 1; i < j; ++ i, -- j) {
std::swap(num[i], num[j]);
}
LL ret = 0;
for (int i = 1; i <= 9 * numlth; ++ i) {
memset(f, -1, sizeof (f));
ret += Dfs(1, 0, 0, true, true, i);
}
// printf("%lld %lld\n", val_, ret);
return ret;
}
//=============================================================
int main() {
LL a = read(), b = read();
printf("%lld\n", Calc(b) - Calc(a - 1));
return 0;
}

套路题们

P3413 SAC#1 - 萌数

给定两个正整数 \(a\) 和 \(b\),求在 \([a,b]\) 中的所有整数中,存在长度至少为2的回文子串的数的个数。

\(1\le a< b\le 10^{1000}\)。

1S,128MB。

存在长度至少为2的回文子串等价于没有连续相等的三位,dfs 时记录前两位即可。代码 Link


「CQOI2016」手机号码

给定两个正整数 \(a\) 和 \(b\),求在 \([a,b]\) 中的所有整数中,至少有三个相邻的相同数字,且 8 和 4 不同时存在的数的个数。

\(10^{10}\le a\le b\le 10^{11}\)。

1S,256MB。

状态多设几维即可,记录前两位,前缀中是否有有三个相邻的相同数字,前缀中是否有 8,前缀中是否有 4。代码 Link


P4317 花神的数论题

给定一正整数 \(a\),求在 \([1,a]\) 中的所有整数的二进制拆分中 1 的个数的乘积。

\(1\le a \le 10^{15}\)。

1S,128MB。

二进制拆分 \(a\),同「AHOI2009」同类分布,枚举二进制中 1 的个数 dfs 即可。

注意不要乱取模。代码 Link

「SDOI2014」数数

给定一个整数 \(n\),一大小为 \(m\) 的数字串集合 \(s\)。

求不以 \(s\) 中任意一个数字串作为子串的,不大于 \(n\) 的数字的个数。

\(1\le n\le 10^{1201}\),\(1\le m\le 100\),\(1\le \sum |s_i|\le 1500\)。\(n\) 没有前导零,\(s_i\) 可能存在前导零。

1S,128MB。

题目要求不以 \(s\) 中任意一个数字串作为子串,想到这题:「JSOI2007」文本生成器。首先套路地对给定集合的串构建 ACAM,并在 ACAM 上标记所有包含集合内的子串的状态。

之后考虑在 ACAM 上模拟串匹配的过程做数位 DP。发现前缀所在状态储存了前缀的所有信息,可以将其作为 dfs 的参数。

Dfs(int now_, int pos_, bool zero_, bool lim_) { 表示前缀匹配到的 ACAM 的状态为 \(\operatorname{pos}\) 时,合法的数字的数量。转移时沿 ACAM 上的转移函数转移,避免转移到被标记的状态。

存在 \(\operatorname{trans}(0, 0) = 0\),这样直接 dfs 也能顺便处理不同长度的数字串。

总复杂度 \(O(\log_{10}(n)\sum |s_i|)\) 级别。

//知识点:ACAM,数位 DP
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <queue>
#define LL long long
const int kN = 1500 + 10;
const int mod = 1e9 + 7;
//=============================================================
int n, m, ans;
char num[kN], s[kN];
//=============================================================
inline int read() {
int f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Chkmax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void Chkmin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
namespace ACAM {
const int kSigma = 10;
int node_num, tr[kN][kSigma], last[kN], fail[kN];
int f[kN][kN];
bool tag[kN];
void Insert(char *s_) {
int u_ = 0, lth = strlen(s_ + 1);
for (int i = 1; i <= lth; ++ i) {
if (! tr[u_][s_[i] - '0']) tr[u_][s_[i] - '0'] = ++ node_num;
u_ = tr[u_][s_[i] - '0'];
last[u_] = s_[i] - '0';
}
tag[u_] = true;
}
void Build() {
std:: queue <int> q;
for (int i = 0; i < kSigma; ++ i) {
if (tr[0][i]) q.push(tr[0][i]);
}
while (!q.empty()) {
int u_ = q.front(); q.pop();
tag[u_] |= tag[fail[u_]];
for (int i = 0; i < kSigma; ++ i) {
int v_ = tr[u_][i];
if (v_) {
fail[v_] = tr[fail[u_]][i];
q.push(v_);
} else {
tr[u_][i] = tr[fail[u_]][i];
}
}
}
}
int Dfs(int now_, int pos_, bool zero_, bool lim_) {
if (now_ > n) return 1;
if (!zero_ && !lim_ && f[now_][pos_] != -1) return f[now_][pos_];
int ret = 0;
for (int i = 0, up = lim_ ? num[now_] - '0': 9; i <= up; ++ i) {
int v_ = tr[pos_][i];
if (tag[v_]) continue;
if (zero_ && !i) ret += Dfs(now_ + 1, 0, true, lim_ && i == num[now_] - '0');
else ret += Dfs(now_ + 1, v_, false, lim_ && i == num[now_] - '0');
ret %= mod;
}
if (!zero_ && !lim_) f[now_][pos_] = ret;
return ret;
}
int DP() {
memset(f, -1, sizeof (f));
return Dfs(1, 0, true, true);
}
}
//=============================================================
int main() {
scanf("%s", num + 1);
n = strlen(num + 1);
m = read();
for (int i = 1; i <= m; ++ i) {
scanf("%s", s + 1);
ACAM::Insert(s);
}
ACAM::Build();
printf("%d\n", ACAM::DP());
return 0;
}

写在最后

鸣谢:

数位dp 笔记 - Flandre-Zhu

「笔记」数位DP的更多相关文章

  1. 「算法笔记」数位 DP

    一.关于数位 dp 有时候我们会遇到某类问题,它所统计的对象具有某些性质,答案在限制/贡献上与统计对象的数位之间有着密切的关系,有可能是数位之间联系的形式,也有可能是数位之间相互独立的形式.(如求满足 ...

  2. 「动态规划」-数位dp专题

    数位dp,今天学长讲的稍玄学,课下花了一会时间仔细看了一下,发现板子是挺好理解的,就在这里写一些: 数位dp主要就是搞一些在区间中,区间内的数满足题目中的条件的数的个数的一类题,题目一般都好理解,这时 ...

  3. 「笔记」AC 自动机

    目录 写在前面 定义 引入 构造 暴力 字典图优化 匹配 在线 离线 复杂度 完整代码 例题 P3796 [模板]AC 自动机(加强版) P3808 [模板]AC 自动机(简单版) 「JSOI2007 ...

  4. 「算法笔记」树形 DP

    一.树形 DP 基础 又是一篇鸽了好久的文章--以下面这道题为例,介绍一下树形 DP 的一般过程. POJ 2342 Anniversary party 题目大意:有一家公司要举行一个聚会,一共有 \ ...

  5. 「算法笔记」期望 DP 入门

    一.数学期望 1. 由来 在 \(17\) 世纪,有一个赌徒向法国著名数学家帕斯卡挑战,给他出了一道题目:甲乙两个人赌博,他们两人获胜的机率相等,比赛规则是先胜三局者为赢家,一共进行五局,赢家可以获得 ...

  6. 「笔记」折半搜索(Meet in the Middle)

    思想 先搜索前一半的状态,再搜索后一半的状态,再记录两边状态相结合的答案. 暴力搜索的时间复杂度通常是 \(O(2^{n})\) 级别的.但折半搜索可以将时间复杂度降到 \(O(2 \times 2^ ...

  7. 「总结」插头$dp$

    集中做完了插头$dp$ 写一下题解. 一开始学的时候还是挺蒙的. 不过后来站在轮廓线$dp$的角度上来看就简单多了. 其实就是一种联通性$dp$,只不过情况比较多而已了. 本来转移方式有两种.逐行和逐 ...

  8. LOJ3102. 「JSOI2019」神经网络 [DP,容斥,生成函数]

    传送门 思路 大部分是感性理解,不保证完全正确. 不能算是神仙题,但我还是不会qwq 这题显然就是求:把每一棵树分成若干条链,然后把链拼成一个环,使得相邻的链不来自同一棵树,的方案数.(我才不告诉你们 ...

  9. LOJ2537. 「PKUWC2018」Minimax [DP,线段树合并]

    传送门 思路 首先有一个\(O(n^2)\)的简单DP:设\(dp_{x,w}\)为\(x\)的权值为\(w\)的概率. 假设\(w\)来自\(v1\)的子树,那么有 \[ dp_{x,w}=dp_{ ...

随机推荐

  1. JAVA 实体类List<Entity >转 List<Map>

    public static <T extends IdEntity> List<Map<Object,Object>> EntityConvertMap(List& ...

  2. 在开发板上显示英文字符和汉字--tiny6410

    程序字符需要改成gb2312.否则无法正常显示中文字符. main.c代码: #include <sys/types.h> #include <sys/stat.h> #inc ...

  3. 收下这款 Vue 项目模版,它将让你的开发效率在 2021 年提高 50%

    这是什么 vue-automation 是一款开箱即用的 Vue 项目模版,它基于 Vue CLI 4 众所周知,虽然 Vue CLI 提供了脚手架的功能,但由于官方的脚手架过于简单,运用在实际项目开 ...

  4. 求你别再用swagger了,给你推荐几个在线文档生成神器

    前言 最近公司打算做一个openapi开放平台,让我找一款好用的在线文档生成工具,具体要求如下: 必须是开源的 能够实时生成在线文档 支持全文搜索 支持在线调试功能 界面优美 说实话,这个需求看起来简 ...

  5. Docker本地镜像仓库搭建Nginx+BusyBox为例

    下载Busybox.Nginx镜像 docker pull busybox docker pull nginx 基于Busybox镜像创建容器,并在容器中做部分变更操作,生成新镜像 添加一些内容 正在 ...

  6. SAML和OAuth2这两种SSO协议的区别

    目录 简介 SAML SAML的缺点 OAuth2 OAuth2的缺点 两者的对比 CAS简介 简介 SSO是单点登录的简称,常用的SSO的协议有两种,分别是SAML和OAuth2.本文将会介绍两种协 ...

  7. Ubuntu 18.04 使用docker 部署gitlab并且使用自定义端口号

    搭建原因 两个月前我搭建了公司的docker(无法自定义端口,),当初只想着把托管在GitHub的项目代码放在公司的服务器上面,后来忙着修改人脸服务器代码,忘记了,这个月由于领导提的需求比较多,还是托 ...

  8. 【Qt】实现程序重启的两种方法

    Qt5/PyQt5 实现程序重启的两种方法 前言 最近在写一个开源项目,需要实现一个程序自动重启的功能.尝试了好几种方式,效果均不太理想. 一开始的实现思路是,记为思路一吧.大概就是写一些 shell ...

  9. LeetCode167 两数之和 II - 输入有序数组

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...

  10. iostat的输出

    第一行显示的时子系统启动以来的平均值,接下来的报告显示了增量的平均值,每个设备一行 Device:         rrqm/s   wrqm/s     r/s     w/s   rsec/s   ...