Loading .remarkrc +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ ["remark-lint-code-block-style", false], ["remark-lint-maximum-line-length", false], ["remark-lint-ordered-list-marker-value", "ordered"], "remark-details", "remark-math", "remark-math-space", "remark-lint-final-newline", Loading docs/basic/binary.md +1 −2 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ int binary_search(int start, int end, int key) { ``` ??? note `>> 1` 比 `/2` 速度快一些 注意,这里的有序是广义的有序,如果一个数组中的左侧或者右侧都满足某一种条件,而另一侧都不满足这种条件,也可以看作是一种有序(如果把满足条件看做 $1$ ,不满足看做 $0$ ,至少对于这个条件的这一维度是有序的)。换言之,二分搜索法可以用来查找满足某种条件的最大(最小)的值。 Loading docs/basic/enumerate.md +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ author: frank-xjh !!! 例题 求小于 N 的最大素数 找不到合适的一个数学公式来直接计算答案,不妨依次尝试一个数是否是答案。 如果我们从大到小枚举小于 $N$ 的数,那么原问题转化为如何判断一个数是不是素数。 Loading docs/dp/knapsack.md +25 −32 Original line number Diff line number Diff line Loading @@ -54,19 +54,16 @@ for (int i = 1; i <= W; i++) ``` ??? 例题代码 ```cpp #include <iostream> const int maxn = 13010; int n, v, w[maxn], v[maxn], f[maxn]; int main() { std::cin >> n >> W; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) for (int l = W; l >= w[i]; l--) if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; std::cout << f[W]; return 0; } Loading Loading @@ -104,19 +101,16 @@ $$ 题意概要:有 $n$ 种物品和一个容量为 $W$ 的背包,每种物品有重量 $w_{i}$ 和价值 $v_{i}$ 两种属性,要求选若干个物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。 ??? 例题代码 ```cpp #include <iostream> const int maxn = 13010; int n, v, w[maxn], v[maxn], f[maxn]; int main() { std::cin >> n >> W; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) for (int l = w[i]; l <= W; l++) if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; std::cout << f[W]; return 0; } Loading Loading @@ -152,7 +146,6 @@ $$ 时间复杂度 $O(nW\sum\log k_i)$ ??? 二进制分组代码 ```cpp index = 0; for (int i = 1; i <= m; i++) { Loading docs/dp/state.md +30 −37 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ ## 例题 ??? note "[「SCOI2005」互不侵犯](https://loj.ac/problem/2153)" 在 $N\times N$ 的棋盘里面放 $K$ 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 $8$ 个格子。 我们用 $f(i,j,l)$ 表示前 $i$ 行,当前状态为 $j$ ,且已经放置 $l$ 个国王时的方案数。 Loading @@ -23,15 +22,13 @@ 需要注意在转移时排除相邻两行国王互相攻击的不合法情况。 ??? "参考代码" ```cpp #include <iostream> #include <algorithm> #include <iostream> using namespace std; long long sta[2005], sit[2005], f[15][2005][105]; int n, k, cnt; void dfs(int x,int num,int cur) { void dfs(int x, int num, int cur) { if (cur >= n) //有新的合法状态 { sit[++cnt] = x; Loading @@ -39,28 +36,24 @@ return; } dfs(x, num, cur + 1); // cur位置不放国王 dfs(x+(1<<cur),num+1,cur+2);//cur位置放国王,与它相邻的位置不能再放国王 dfs(x + (1 << cur), num + 1, cur + 2); // cur位置放国王,与它相邻的位置不能再放国王 } int main() { int main() { cin >> n >> k; dfs(0, 0, 0); //先预处理一行的所有合法状态 for(int i=1;i<=cnt;i++) f[1][i][sta[i]]=1; for (int i = 1; i <= cnt; i++) f[1][i][sta[i]] = 1; for (int i = 2; i <= n; i++) for (int j = 1; j <= cnt; j++) for(int l=1;l<=cnt;l++) { for (int l = 1; l <= cnt; l++) { if (sit[j] & sit[l]) continue; if ((sit[j] << 1) & sit[l]) continue; if (sit[j] & (sit[l] << 1)) continue; //排除不合法转移 for(int p=sta[j];p<=k;p++) f[i][j][p]+=f[i-1][l][p-sta[j]]; for (int p = sta[j]; p <= k; p++) f[i][j][p] += f[i - 1][l][p - sta[j]]; } long long ans = 0; for(int i=1;i<=cnt;i++) ans+=f[n][i][k];//累加答案 for (int i = 1; i <= cnt; i++) ans += f[n][i][k]; //累加答案 cout << ans << endl; return 0; } Loading Loading
.remarkrc +1 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ ["remark-lint-code-block-style", false], ["remark-lint-maximum-line-length", false], ["remark-lint-ordered-list-marker-value", "ordered"], "remark-details", "remark-math", "remark-math-space", "remark-lint-final-newline", Loading
docs/basic/binary.md +1 −2 Original line number Diff line number Diff line Loading @@ -30,7 +30,6 @@ int binary_search(int start, int end, int key) { ``` ??? note `>> 1` 比 `/2` 速度快一些 注意,这里的有序是广义的有序,如果一个数组中的左侧或者右侧都满足某一种条件,而另一侧都不满足这种条件,也可以看作是一种有序(如果把满足条件看做 $1$ ,不满足看做 $0$ ,至少对于这个条件的这一维度是有序的)。换言之,二分搜索法可以用来查找满足某种条件的最大(最小)的值。 Loading
docs/basic/enumerate.md +1 −0 Original line number Diff line number Diff line Loading @@ -4,6 +4,7 @@ author: frank-xjh !!! 例题 求小于 N 的最大素数 找不到合适的一个数学公式来直接计算答案,不妨依次尝试一个数是否是答案。 如果我们从大到小枚举小于 $N$ 的数,那么原问题转化为如何判断一个数是不是素数。 Loading
docs/dp/knapsack.md +25 −32 Original line number Diff line number Diff line Loading @@ -54,19 +54,16 @@ for (int i = 1; i <= W; i++) ``` ??? 例题代码 ```cpp #include <iostream> const int maxn = 13010; int n, v, w[maxn], v[maxn], f[maxn]; int main() { std::cin >> n >> W; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) for (int l = W; l >= w[i]; l--) if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; std::cout << f[W]; return 0; } Loading Loading @@ -104,19 +101,16 @@ $$ 题意概要:有 $n$ 种物品和一个容量为 $W$ 的背包,每种物品有重量 $w_{i}$ 和价值 $v_{i}$ 两种属性,要求选若干个物品放入背包使背包中物品的总价值最大且背包中物品的总重量不超过背包的容量。 ??? 例题代码 ```cpp #include <iostream> const int maxn = 13010; int n, v, w[maxn], v[maxn], f[maxn]; int main() { std::cin >> n >> W; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) std::cin >> w[i] >> v[i]; for (int i = 1; i <= n; i++) for (int l = w[i]; l <= W; l++) if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; if (f[l - w[i]] + v[i] > f[l]) f[l] = f[l - w[i]] + v[i]; std::cout << f[W]; return 0; } Loading Loading @@ -152,7 +146,6 @@ $$ 时间复杂度 $O(nW\sum\log k_i)$ ??? 二进制分组代码 ```cpp index = 0; for (int i = 1; i <= m; i++) { Loading
docs/dp/state.md +30 −37 Original line number Diff line number Diff line Loading @@ -9,7 +9,6 @@ ## 例题 ??? note "[「SCOI2005」互不侵犯](https://loj.ac/problem/2153)" 在 $N\times N$ 的棋盘里面放 $K$ 个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共 $8$ 个格子。 我们用 $f(i,j,l)$ 表示前 $i$ 行,当前状态为 $j$ ,且已经放置 $l$ 个国王时的方案数。 Loading @@ -23,15 +22,13 @@ 需要注意在转移时排除相邻两行国王互相攻击的不合法情况。 ??? "参考代码" ```cpp #include <iostream> #include <algorithm> #include <iostream> using namespace std; long long sta[2005], sit[2005], f[15][2005][105]; int n, k, cnt; void dfs(int x,int num,int cur) { void dfs(int x, int num, int cur) { if (cur >= n) //有新的合法状态 { sit[++cnt] = x; Loading @@ -39,28 +36,24 @@ return; } dfs(x, num, cur + 1); // cur位置不放国王 dfs(x+(1<<cur),num+1,cur+2);//cur位置放国王,与它相邻的位置不能再放国王 dfs(x + (1 << cur), num + 1, cur + 2); // cur位置放国王,与它相邻的位置不能再放国王 } int main() { int main() { cin >> n >> k; dfs(0, 0, 0); //先预处理一行的所有合法状态 for(int i=1;i<=cnt;i++) f[1][i][sta[i]]=1; for (int i = 1; i <= cnt; i++) f[1][i][sta[i]] = 1; for (int i = 2; i <= n; i++) for (int j = 1; j <= cnt; j++) for(int l=1;l<=cnt;l++) { for (int l = 1; l <= cnt; l++) { if (sit[j] & sit[l]) continue; if ((sit[j] << 1) & sit[l]) continue; if (sit[j] & (sit[l] << 1)) continue; //排除不合法转移 for(int p=sta[j];p<=k;p++) f[i][j][p]+=f[i-1][l][p-sta[j]]; for (int p = sta[j]; p <= k; p++) f[i][j][p] += f[i - 1][l][p - sta[j]]; } long long ans = 0; for(int i=1;i<=cnt;i++) ans+=f[n][i][k];//累加答案 for (int i = 1; i <= cnt; i++) ans += f[n][i][k]; //累加答案 cout << ans << endl; return 0; } Loading