动态规划基础与一维动态规划
动态规划基础与一维动态规划
动态规划的基本思路;简单一维动态规划。
概念
动态规划把原问题拆成重叠子问题,按阶段填表,每格存最优或方案数,利用已算结果避免重复枚举。一维 DP 最常见:dp[i] 表示考虑前 i 个元素、或到达位置 i 的最优值,转移来自 dp[i-1]、dp[i-2] 或若干前驱。识别关键是「最优子结构 + 无后效性」——当前决策只依赖已记录状态。与 cspj.algo.dp-knapsack-interval 区分:后者是背包(选/不选)或区间合并类 DP;与 cspj.algo.recurrence-and-recursion 区分:递推可以是 DP 的实现方式,但 DP 强调多候选取 max/min 或计数。与 cspj.algo.greedy 区分:DP 会同时保留多种子结构的结果。
CSP-J 常考
cspj-r1-2023第 21–22、38–42 题:阅读/完善程序,一维 DP 数组定义、转移与初值填空。cspj-r1-2024第 21、23–26 题:阅读程序,tracedp[i]或完善转移式。cspj-r1-2025第 22–23、25–26、28–33 题:本课该叶子题量最多,完善程序与阅读程序集中考查 DP 填表。cspj-r2-2019第 3 题:复赛编程,逐日买卖求第 T 天最多金币,状态转移 DP。cspj-r2-2024第 3 题:复赛编程,每位数字固定棍数代价,构造最小正整数的一维 DP。
// 爬楼梯:到第 i 阶的方案数 = 到 i-1 + 到 i-2
int dp[20];
dp[1] = 1; dp[2] = 2;
for (int i = 3; i <= n; ++i)
dp[i] = dp[i-1] + dp[i-2];
// 若求最小代价,转移里用 min 而非 +
易错点
- 初值
dp[0]、dp[1]与题意不符,完善程序只改一行转移却忽略边界。 - 循环方向错:需要
dp[i-1]已算完时,i 应从小到大;若依赖后面状态则要反过来。 - 把「递推求项」与「DP 求最值」混淆,阅读程序里出现
max/min时要找决策分支。
纪念品
C++时间 1 s内存 256 MB 文件 IO:souvenir.in → souvenir.out
小伟突然获得一种超能力,他知道未来 T 天 N 种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。
每天,小伟可以进行以下两种交易无限次:
- 任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
- 卖出持有的任意一个纪念品,以当日价格换回金币。
每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。
T 天之后,小伟的超能力消失。因此他一定会在第 T 天卖出所有纪念品换回金币。
小伟现在有 M 枚金币,他想要在超能力消失后拥有尽可能多的金币。
输入格式
第一行包含三个正整数 T,N,M,相邻两数之间以一个空格分开,分别代表未来天数 T,纪念品数量 N,小伟现在拥有的金币数量 M。
接下来 T 行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i 行的 N 个正整数分别为 Pi,1,Pi,2,…,Pi,N,其中 Pi,j 表示第 i 天第 j 种纪念品的价格。
输出格式
输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
样例
6 1 100 50 20 25 20 25 50
305
最佳策略是:
第二天花光所有 100 枚金币买入 5 个纪念品 1;
第三天卖出 5 个纪念品 1,获得金币 125 枚;
第四天买入 6 个纪念品 1,剩余 5 枚金币;
第六天必须卖出所有纪念品换回 300 枚金币,第四天剩余 5 枚金币,共 305 枚金币。
超能力消失后,小伟最多拥有 305 枚金币。
3 3 100 10 20 15 15 17 13 15 25 16
217
最佳策略是:
第一天花光所有金币买入 10 个纪念品 1;
第二天卖出全部纪念品 1 得到 150 枚金币并买入 8 个纪念品 2 和 1 个纪念品 3,剩余 1 枚金币;
第三天必须卖出所有纪念品换回 216 枚金币,第二天剩余 1 枚金币,共 217 枚金币。
超能力消失后,小伟最多拥有 217 枚金币。
数据范围
对于 10% 的数据,T=1。
对于 30% 的数据,T≤4,N≤4,M≤100,所有价格 10≤Pi,j≤100。
另有 15% 的数据,T≤100,N=1。
另有 15% 的数据,T=2,N≤100。
对于 100% 的数据,T≤100,N≤100,M≤103,所有价格 1≤Pi,j≤104,数据保证任意时刻,小明手上的金币数不可能超过 104。
部分分
- 100 分
全部 20 个测试点等分;数据范围见 constraintsMd 各百分比档。
原文保真说明:原卷印刷错误 1 处(照原卷保留,未作修改)
原卷印刷如此符号不一致数据范围
原卷作
小明手上的金币数,常规写法应为小伟手上的金币数原卷第 7 页【数据规模与约定】末句印作「小明」,题面正文(第 6 页)与样例解释均作「小伟」。constraintsMd 按第 7 页图像照录「小明」;原卷印刷不一致已如实记录。
你的代码(C++)
提交后由评测机编译运行,结果见下方76 B / 64 KB
判题结果
方格取数
C++时间 1 s内存 256 MB 文件 IO:number.in → number.out
设有 n×m 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。
输入格式
从文件 number.in 中读入数据。
第一行有两个正整数 n,m。
接下来 n 行,每行 m 个整数,依次代表每个方格中的整数。
输出格式
输出到文件 number.out 中。
输出一行一个整数,表示小熊能取到的整数之和的最大值。
样例
3 4 1 -1 3 2 2 -1 4 -1 -2 2 -3 -1
9
按走法 (1,1)→(2,1)→(2,2)→(2,3)→(1,3)→(1,4)→(2,4)→(3,4),取到的数之和为 1+2+(−1)+4+3+2+(−1)+(−1)=9,可以证明为最大值。原卷【样例 1 解释】含路径示意图(pg-08),此处仅转写文字说明。
2 5 -1 -1 -3 -2 -7 -2 -1 -4 -1 -2
-10
按走法 (1,1)→(1,2)→(1,3)→(1,4)→(2,4)→(2,5),取到的数之和为 (−1)+(−1)+(−3)+(−2)+(−1)+(−2)=−10,可以证明为最大值。因此,取到的数之和的最大值也可能是负数。原卷【样例 2 解释】含路径示意图(pg-09)。
数据范围
对于 20% 的数据,n,m≤5。
对于 40% 的数据,n,m≤50。
对于 70% 的数据,n,m≤300。
对于 100% 的数据,1≤n,m≤103。方格中整数的绝对值不超过 104。
部分分
- 100 分
全部 20 个测试点等分;数据范围见 constraintsMd 各百分比档。
你的代码(C++)
提交后由评测机编译运行,结果见下方76 B / 64 KB
判题结果
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
1 #include <algorithm>22 #include <iostream>33 #include <limits>44 55 using namespace std;66 77 const int MAXN = 105;88 const int MAXK = 105;99 1010 int h[MAXN][MAXK];1111 1212 int f(int n, int m)1313 {1414 if (m == 1) return n;1515 if (n == 0) return 0;1616 1717 int ret = numeric_limits<int>::max();1818 for (int i = 1; i <= n; i++)1919 ret = min(ret, max(f(n - i,m), f(i - 1, m - 1)) + 1);2020 return ret;2121 }2222 2323 int g(int n, int m)2424 {2525 for (int i = 1;i <= n; i++)2626 h[i][1]= i;2727 for (int j = 1;j<= m; j++)2828 h[0][j]= 0;2929 3030 for (int i= 1; i <= n; i++){3131 for (int j= 2; j <= m; j++){3232 h[i][j] = numeric_limits<int>::max();3333 for (int k = 1;k <= i;k++)3434 h[i][j]= min(3535 h[i][j],3636 max(h[i - k][j],h[k - 1][j - 1]) +1);3737 }3838 }3939 4040 return h[n][m];4141 }4242 4343 int main()4444 {4545 int n,m;4646 cin >> n>> m;4747 cout << f(n, m) << endl << g(n, m)<< endl;4848 return 0;4949 }- 23判断1.5 分
输出的两行整数总是相同的。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
1 #include <algorithm>22 #include <iostream>33 #include <limits>44 55 using namespace std;66 77 const int MAXN = 105;88 const int MAXK = 105;99 1010 int h[MAXN][MAXK];1111 1212 int f(int n, int m)1313 {1414 if (m == 1) return n;1515 if (n == 0) return 0;1616 1717 int ret = numeric_limits<int>::max();1818 for (int i = 1; i <= n; i++)1919 ret = min(ret, max(f(n - i,m), f(i - 1, m - 1)) + 1);2020 return ret;2121 }2222 2323 int g(int n, int m)2424 {2525 for (int i = 1;i <= n; i++)2626 h[i][1]= i;2727 for (int j = 1;j<= m; j++)2828 h[0][j]= 0;2929 3030 for (int i= 1; i <= n; i++){3131 for (int j= 2; j <= m; j++){3232 h[i][j] = numeric_limits<int>::max();3333 for (int k = 1;k <= i;k++)3434 h[i][j]= min(3535 h[i][j],3636 max(h[i - k][j],h[k - 1][j - 1]) +1);3737 }3838 }3939 4040 return h[n][m];4141 }4242 4343 int main()4444 {4545 int n,m;4646 cin >> n>> m;4747 cout << f(n, m) << endl << g(n, m)<< endl;4848 return 0;4949 }- 25单选3 分
单选题
- 算法 g(n,m) 最为准确的时间复杂度分析结果为( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
1 #include <algorithm>22 #include <iostream>33 #include <limits>44 55 using namespace std;66 77 const int MAXN = 105;88 const int MAXK = 105;99 1010 int h[MAXN][MAXK];1111 1212 int f(int n, int m)1313 {1414 if (m == 1) return n;1515 if (n == 0) return 0;1616 1717 int ret = numeric_limits<int>::max();1818 for (int i = 1; i <= n; i++)1919 ret = min(ret, max(f(n - i,m), f(i - 1, m - 1)) + 1);2020 return ret;2121 }2222 2323 int g(int n, int m)2424 {2525 for (int i = 1;i <= n; i++)2626 h[i][1]= i;2727 for (int j = 1;j<= m; j++)2828 h[0][j]= 0;2929 3030 for (int i= 1; i <= n; i++){3131 for (int j= 2; j <= m; j++){3232 h[i][j] = numeric_limits<int>::max();3333 for (int k = 1;k <= i;k++)3434 h[i][j]= min(3535 h[i][j],3636 max(h[i - k][j],h[k - 1][j - 1]) +1);3737 }3838 }3939 4040 return h[n][m];4141 }4242 4343 int main()4444 {4545 int n,m;4646 cin >> n>> m;4747 cout << f(n, m) << endl << g(n, m)<< endl;4848 return 0;4949 }- 26单选3 分
当输入为
20 2时,输出的第一行为( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
1 #include <algorithm>22 #include <iostream>33 #include <limits>44 55 using namespace std;66 77 const int MAXN = 105;88 const int MAXK = 105;99 1010 int h[MAXN][MAXK];1111 1212 int f(int n, int m)1313 {1414 if (m == 1) return n;1515 if (n == 0) return 0;1616 1717 int ret = numeric_limits<int>::max();1818 for (int i = 1; i <= n; i++)1919 ret = min(ret, max(f(n - i,m), f(i - 1, m - 1)) + 1);2020 return ret;2121 }2222 2323 int g(int n, int m)2424 {2525 for (int i = 1;i <= n; i++)2626 h[i][1]= i;2727 for (int j = 1;j<= m; j++)2828 h[0][j]= 0;2929 3030 for (int i= 1; i <= n; i++){3131 for (int j= 2; j <= m; j++){3232 h[i][j] = numeric_limits<int>::max();3333 for (int k = 1;k <= i;k++)3434 h[i][j]= min(3535 h[i][j],3636 max(h[i - k][j],h[k - 1][j - 1]) +1);3737 }3838 }3939 4040 return h[n][m];4141 }4242 4343 int main()4444 {4545 int n,m;4646 cin >> n>> m;4747 cout << f(n, m) << endl << g(n, m)<< endl;4848 return 0;4949 }- 27单选4 分
(4 分) 当输入
100 100时,输出的第一行为( )。
上升点列
C++时间 1 s内存 512 MB 文件 IO:point.in → point.out
在一个二维平面内,给定 n 个整数点 (xi,yi),此外你还可以自由添加 k 个整数点。
你在自由添加 k 个点后,还需要从 n+k 个点中选出若干个整数点并组成一个序列,使得序列中任意相邻两点间的欧几里得距离恰好为 1 而且横坐标、纵坐标值均单调不减,即 xi+1−xi=1,yi+1=yi 或 yi+1−yi=1,xi+1=xi。请给出满足条件的序列的最大长度。
输入格式
从文件 point.in 中读入数据。
第一行两个正整数 n,k 分别表示给定的整点个数、可自由添加的整点个数。
接下来 n 行,第 i 行两个正整数 xi,yi 表示给定的第 i 个点的横纵坐标。
输出格式
输出到文件 point.out 中。
输出一个整数表示满足要求的序列的最大长度。
样例
8 2 3 1 3 2 3 3 3 6 1 2 2 2 5 5 5 3
8
4 100 10 10 15 25 20 20 30 30
103
数据范围
对于所有数据满足:1≤n≤500,0≤k≤100。对于所有给定的整点,其横纵坐标 1≤xi,yi≤109,且保证所有给定的点互不重合。对于自由添加的整点,其横纵坐标不受限制。
| 测试点编号 | n≤ | k≤ | xi,yi≤ |
|---|---|---|---|
| 1∼2 | 10 | 0 | 10 |
| 3∼4 | 10 | 100 | 100 |
| 5∼7 | 500 | 0 | 100 |
| 8∼10 | 500 | 0 | 109 |
| 11∼15 | 500 | 100 | 100 |
| 16∼20 | 500 | 100 | 109 |
部分分
- 10 分
测试点 1∼2:n≤10,k≤0,xi,yi≤10。
- 10 分
测试点 3∼4:n≤10,k≤100,xi,yi≤100。
- 15 分
测试点 5∼7:n≤500,k≤0,xi,yi≤100。
- 15 分
测试点 8∼10:n≤500,k≤0,xi,yi≤109。
- 25 分
测试点 11∼15:n≤500,k≤100,xi,yi≤100。
- 25 分
测试点 16∼20:n≤500,k≤100,xi,yi≤109。
原文保真说明:来源改写 1 处(照原卷保留,未作修改)
来源题面被改写其它数据范围
原卷作
| $16 \sim 20$ | $500$ | $100$ | ${10}^9$ |,常规写法应为| $15 \sim 20$ | $500$ | $100$ | ${10}^9$ |官方 PDF 第 10 页测试点表末行印作 $15 \sim 20$,与上一行 $11 \sim 15$ 重叠;结合共 $20$ 个等分测试点,恢复为 $16 \sim 20$。
已按官方原件恢复:现为原卷原文
你的代码(C++)
提交后由评测机编译运行,结果见下方76 B / 64 KB
判题结果
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include<iostream>2#include<vector>3#include<algorithm>4using namespace std;56int f(string x,string y){7 int m=x.size();8 int n=y.size();9 vector<vector<int>>v(m+1,vector<int>(n+1,0));10 for(int i=1;i<=m;i++){11 for(int j=1;j<=n;j++){12 if(x[i-1]==y[j-1]){13 v[i][j]=v[i-1][j-1]+1;14 }else{15 v[i][j]=max(v[i-1][j],v[i][j-1]);16 }17 }18 }19 return v[m][n];20}21bool g(string x,string y){22 if(x.size() != y.size()){23 return false;24 }25 return f(x+x,y)==y.size();26}27int main(){28 string x,y;29 cin>>x>>y;30 cout<<g(x,y)<<endl;31 return 0;32}- 21判断1.5 分
f函数的返回值小于等于 min{n,m}。()
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include<iostream>2#include<vector>3#include<algorithm>4using namespace std;56int f(string x,string y){7 int m=x.size();8 int n=y.size();9 vector<vector<int>>v(m+1,vector<int>(n+1,0));10 for(int i=1;i<=m;i++){11 for(int j=1;j<=n;j++){12 if(x[i-1]==y[j-1]){13 v[i][j]=v[i-1][j-1]+1;14 }else{15 v[i][j]=max(v[i-1][j],v[i][j-1]);16 }17 }18 }19 return v[m][n];20}21bool g(string x,string y){22 if(x.size() != y.size()){23 return false;24 }25 return f(x+x,y)==y.size();26}27int main(){28 string x,y;29 cin>>x>>y;30 cout<<g(x,y)<<endl;31 return 0;32}- 22判断1.5 分
f函数的返回值等于两个输入字符串的最长公共子串的长度。()
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
- (编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace),一个字符,求将第一个字符串转换为第二个字符串所需要的最少操作次数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int min(int x, int y, int z) {
return min(min(x, y), z);
}
int edit_dist_dp(string str1, string str2) {
int m = str1.length();
int n = str2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = ①;
else if (j == 0)
dp[i][j] = ②;
else if (③)
dp[i][j] = ④;
else
dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
}
}
return dp[m][n];
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;
return 0;
}
#include <iostream>2#include <string>3#include <vector>4using namespace std;5int min(int x, int y, int z) {6 return min(min(x, y), z);7}8int edit_dist_dp(string str1, string str2) {9 int m = str1.length();10 int n = str2.length();11 vector<vector<int>> dp(m + 1, vector<int>(n + 1));12 for (int i = 0; i <= m; i++) {13 for (int j = 0; j <= n; j++) {14 if (i == 0)15 dp[i][j] = ①;16 else if (j == 0)17 dp[i][j] = ②;18 else if (③)19 dp[i][j] = ④;20 else21 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);22 }23 }24 return dp[m][n];25}26int main() {27 string str1, str2;28 cin >> str1 >> str2;29 cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;30 return 0;31}- 38(①)单选空位 ①3 分
①处应填( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
- (编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace),一个字符,求将第一个字符串转换为第二个字符串所需要的最少操作次数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int min(int x, int y, int z) {
return min(min(x, y), z);
}
int edit_dist_dp(string str1, string str2) {
int m = str1.length();
int n = str2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = ①;
else if (j == 0)
dp[i][j] = ②;
else if (③)
dp[i][j] = ④;
else
dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
}
}
return dp[m][n];
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;
return 0;
}
#include <iostream>2#include <string>3#include <vector>4using namespace std;5int min(int x, int y, int z) {6 return min(min(x, y), z);7}8int edit_dist_dp(string str1, string str2) {9 int m = str1.length();10 int n = str2.length();11 vector<vector<int>> dp(m + 1, vector<int>(n + 1));12 for (int i = 0; i <= m; i++) {13 for (int j = 0; j <= n; j++) {14 if (i == 0)15 dp[i][j] = ①;16 else if (j == 0)17 dp[i][j] = ②;18 else if (③)19 dp[i][j] = ④;20 else21 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);22 }23 }24 return dp[m][n];25}26int main() {27 string str1, str2;28 cin >> str1 >> str2;29 cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;30 return 0;31}- 39(②)单选空位 ②3 分
②处应填( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
- (编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace),一个字符,求将第一个字符串转换为第二个字符串所需要的最少操作次数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int min(int x, int y, int z) {
return min(min(x, y), z);
}
int edit_dist_dp(string str1, string str2) {
int m = str1.length();
int n = str2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = ①;
else if (j == 0)
dp[i][j] = ②;
else if (③)
dp[i][j] = ④;
else
dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
}
}
return dp[m][n];
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;
return 0;
}
#include <iostream>2#include <string>3#include <vector>4using namespace std;5int min(int x, int y, int z) {6 return min(min(x, y), z);7}8int edit_dist_dp(string str1, string str2) {9 int m = str1.length();10 int n = str2.length();11 vector<vector<int>> dp(m + 1, vector<int>(n + 1));12 for (int i = 0; i <= m; i++) {13 for (int j = 0; j <= n; j++) {14 if (i == 0)15 dp[i][j] = ①;16 else if (j == 0)17 dp[i][j] = ②;18 else if (③)19 dp[i][j] = ④;20 else21 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);22 }23 }24 return dp[m][n];25}26int main() {27 string str1, str2;28 cin >> str1 >> str2;29 cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;30 return 0;31}- 40(③)单选空位 ③3 分
③处应填( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
- (编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace),一个字符,求将第一个字符串转换为第二个字符串所需要的最少操作次数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int min(int x, int y, int z) {
return min(min(x, y), z);
}
int edit_dist_dp(string str1, string str2) {
int m = str1.length();
int n = str2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = ①;
else if (j == 0)
dp[i][j] = ②;
else if (③)
dp[i][j] = ④;
else
dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
}
}
return dp[m][n];
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;
return 0;
}
#include <iostream>2#include <string>3#include <vector>4using namespace std;5int min(int x, int y, int z) {6 return min(min(x, y), z);7}8int edit_dist_dp(string str1, string str2) {9 int m = str1.length();10 int n = str2.length();11 vector<vector<int>> dp(m + 1, vector<int>(n + 1));12 for (int i = 0; i <= m; i++) {13 for (int j = 0; j <= n; j++) {14 if (i == 0)15 dp[i][j] = ①;16 else if (j == 0)17 dp[i][j] = ②;18 else if (③)19 dp[i][j] = ④;20 else21 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);22 }23 }24 return dp[m][n];25}26int main() {27 string str1, str2;28 cin >> str1 >> str2;29 cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;30 return 0;31}- 41(④)单选空位 ④3 分
④处应填( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
- (编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace),一个字符,求将第一个字符串转换为第二个字符串所需要的最少操作次数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int min(int x, int y, int z) {
return min(min(x, y), z);
}
int edit_dist_dp(string str1, string str2) {
int m = str1.length();
int n = str2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (i == 0)
dp[i][j] = ①;
else if (j == 0)
dp[i][j] = ②;
else if (③)
dp[i][j] = ④;
else
dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
}
}
return dp[m][n];
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;
return 0;
}
#include <iostream>2#include <string>3#include <vector>4using namespace std;5int min(int x, int y, int z) {6 return min(min(x, y), z);7}8int edit_dist_dp(string str1, string str2) {9 int m = str1.length();10 int n = str2.length();11 vector<vector<int>> dp(m + 1, vector<int>(n + 1));12 for (int i = 0; i <= m; i++) {13 for (int j = 0; j <= n; j++) {14 if (i == 0)15 dp[i][j] = ①;16 else if (j == 0)17 dp[i][j] = ②;18 else if (③)19 dp[i][j] = ④;20 else21 dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);22 }23 }24 return dp[m][n];25}26int main() {27 string str1, str2;28 cin >> str1 >> str2;29 cout << "Minimum number of operations: " << edit_dist_dp(str1, str2) << endl;30 return 0;31}- 42(⑤)单选空位 ⑤3 分
⑤处应填( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 √,错误填 ×
#include <iostream>2#include <vector>3using namespace std;45int compute(vector<int>& cost) {6 int n = cost.size();7 vector<int> dp(n+1, 0);8 dp[1] = cost[0];9 for (int i = 2; i <= n; i++) {10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];11 }12 return min(dp[n], dp[n-1]);13}1415int main() {16 int n;17 cin >> n;18 vector<int> cost(n);19 for (int i = 0; i < n; i++) {20 cin >> cost[i];21 }22 cout << compute(cost) << endl;23 return 0;24}- 21判断1.5 分
当输入的
cost数组为 {10,15,20} 时,程序的输出为 15。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 √,错误填 ×
#include <iostream>2#include <vector>3using namespace std;45int compute(vector<int>& cost) {6 int n = cost.size();7 vector<int> dp(n+1, 0);8 dp[1] = cost[0];9 for (int i = 2; i <= n; i++) {10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];11 }12 return min(dp[n], dp[n-1]);13}1415int main() {16 int n;17 cin >> n;18 vector<int> cost(n);19 for (int i = 0; i < n; i++) {20 cin >> cost[i];21 }22 cout << compute(cost) << endl;23 return 0;24}- 23判断2 分
(2 分)程序总是输出
cost数组中最小的元素。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <iostream>2#include <vector>3using namespace std;45int compute(vector<int>& cost) {6 int n = cost.size();7 vector<int> dp(n+1, 0);8 dp[1] = cost[0];9 for (int i = 2; i <= n; i++) {10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];11 }12 return min(dp[n], dp[n-1]);13}1415int main() {16 int n;17 cin >> n;18 vector<int> cost(n);19 for (int i = 0; i < n; i++) {20 cin >> cost[i];21 }22 cout << compute(cost) << endl;23 return 0;24}- 24单选3 分
单选题
- 当输入的
cost数组为 {1,100,1,1,1,100,1,1,100,1} 时,程序的输出为( )。
- 当输入的
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <iostream>2#include <vector>3using namespace std;45int compute(vector<int>& cost) {6 int n = cost.size();7 vector<int> dp(n+1, 0);8 dp[1] = cost[0];9 for (int i = 2; i <= n; i++) {10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];11 }12 return min(dp[n], dp[n-1]);13}1415int main() {16 int n;17 cin >> n;18 vector<int> cost(n);19 for (int i = 0; i < n; i++) {20 cin >> cost[i];21 }22 cout << compute(cost) << endl;23 return 0;24}- 25单选4 分
(4 分)如果输入的
cost数组为 {10,15,30,5,5,10,20},程序的输出为( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <iostream>2#include <vector>3using namespace std;45int compute(vector<int>& cost) {6 int n = cost.size();7 vector<int> dp(n+1, 0);8 dp[1] = cost[0];9 for (int i = 2; i <= n; i++) {10 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];11 }12 return min(dp[n], dp[n-1]);13}1415int main() {16 int n;17 cin >> n;18 vector<int> cost(n);19 for (int i = 0; i < n; i++) {20 cin >> cost[i];21 }22 cout << compute(cost) << endl;23 return 0;24}- 26单选3 分
若将代码中的
min(dp[i-1], dp[i-2]) + cost[i-1]修改为dp[i-1] + cost[i-2],输入cost数组为 {5,10,15} 时,程序的输出为( )。
小木棍
C++时间 1 s内存 512 MB 文件 IO:sticks.in → sticks.out
小 S 喜欢收集小木棍。在收集了 n 根长度相等的小木棍之后,他闲来无事,便用它们拼起了数字。用小木棍拼每种数字的方法如下图所示。

现在小 S 希望拼出一个正整数,满足如下条件:
- 拼出这个数恰好使用 n 根小木棍;
- 拼出的数没有前导 0;
- 在满足以上两个条件的前提下,这个数尽可能小。
小 S 想知道这个数是多少,可 n 很大,把木棍整理清楚就把小 S 折腾坏了,所以你需要帮他解决这个问题。如果不存在正整数满足以上条件,你需要输出 −1 进行报告。
输入格式
从文件 sticks.in 中读入数据。
本题有多组测试数据。
输入的第一行包含一个正整数 T,表示数据组数。
接下来包含 T 组数据,每组数据的格式如下:
一行包含一个整数 n,表示木棍数。
输出格式
输出到文件 sticks.out 中。
对于每组数据:输出一行,如果存在满足题意的正整数,输出这个数;否则输出 −1。
样例
5 1 2 3 6 18
-1 1 7 6 208
- 对于第一组测试数据,不存在任何一个正整数可以使用恰好一根小木棍摆出,故输出 −1。
- 对于第四组测试数据,注意 0 并不是一个满足要求的方案。摆出 9、41 以及 111 都恰好需要 6 根小木棍,但它们不是摆出的数最小的方案。
- 对于第五组测试数据,摆出 208 需要 5+6+7=18 根小木棍。可以证明摆出任何一个小于 208 的正整数需要的小木棍数都不是 18。注意尽管拼出 006 也需要 18 根小木棍,但因为这个数有前导零,因此并不是一个满足要求的方案。
数据范围
对于所有测试数据,保证:1≤T≤50,1≤n≤105。
| 测试点编号 | n≤ | 特殊性质 |
|---|---|---|
| 1 | 20 | 无 |
| 2 | 50 | 无 |
| 3 | 103 | A |
| 4,5 | 105 | A |
| 6 | 103 | B |
| 7,8 | 105 | B |
| 9 | 103 | 无 |
| 10 | 105 | 无 |
特殊性质 A:保证 n 是 7 的倍数且 n≥100。
特殊性质 B:保证存在整数 k 使得 n=7k+1,且 n≥100。
部分分
- 10 分
测试点 1:n≤20,无特殊性质。
- 10 分
测试点 2:n≤50,无特殊性质。
- 10 分
测试点 3:n≤103,特殊性质 A。
- 20 分
测试点 4,5:n≤105,无特殊性质。
- 10 分
测试点 6:n≤103,特殊性质 B。
- 20 分
测试点 7,8:n≤105,无特殊性质。
- 10 分
测试点 9:n≤103,无特殊性质。
- 10 分
测试点 10:n≤105,无特殊性质。
你的代码(C++)
提交后由评测机编译运行,结果见下方76 B / 64 KB
判题结果
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 A,错误填 B
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int n, k;6int a[200007];7int ans[200007];8int main() {9 scanf("%d%d", &n, &k);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 std::sort(a + 1, a + n + 1);14 n = std::unique(a + 1, a + n + 1) - a - 1;15 for (int i = 1, j = 0; i <= n; ++i) {16 for (; j < i && a[i] - a[j + 1] > k; ++j)17 ;18 ans[i] = ans[j] + 1;19 }20 printf("%d\n", ans[n]);21 return 0;22}- 22判断1.5 分
当输入为
3 1 3 2 1时,输出结果为 2。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 A,错误填 B
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int n, k;6int a[200007];7int ans[200007];8int main() {9 scanf("%d%d", &n, &k);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 std::sort(a + 1, a + n + 1);14 n = std::unique(a + 1, a + n + 1) - a - 1;15 for (int i = 1, j = 0; i <= n; ++i) {16 for (; j < i && a[i] - a[j + 1] > k; ++j)17 ;18 ans[i] = ans[j] + 1;19 }20 printf("%d\n", ans[n]);21 return 0;22}- 23判断1.5 分
假设输入的 n 为正整数,输出的答案一定小于等于 n,大于等于 1。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int n, k;6int a[200007];7int ans[200007];8int main() {9 scanf("%d%d", &n, &k);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 std::sort(a + 1, a + n + 1);14 n = std::unique(a + 1, a + n + 1) - a - 1;15 for (int i = 1, j = 0; i <= n; ++i) {16 for (; j < i && a[i] - a[j + 1] > k; ++j)17 ;18 ans[i] = ans[j] + 1;19 }20 printf("%d\n", ans[n]);21 return 0;22}- 25单选3 分
假设输入的 a 数组和 k 均为正整数,执行第 18 行代码时,一定满足的条件不包括( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int n, k;6int a[200007];7int ans[200007];8int main() {9 scanf("%d%d", &n, &k);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 std::sort(a + 1, a + n + 1);14 n = std::unique(a + 1, a + n + 1) - a - 1;15 for (int i = 1, j = 0; i <= n; ++i) {16 for (; j < i && a[i] - a[j + 1] > k; ++j)17 ;18 ans[i] = ans[j] + 1;19 }20 printf("%d\n", ans[n]);21 return 0;22}- 26单选3 分
当输入的 n=100、k=2、a={1,2,…,100} 时,输出为( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 A,错误填 B
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 28判断1.5 分
当输入
4 1 2 3 4 1 3 2 2时,输出为 2。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 A,错误填 B
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 29判断1.5 分
当程序运行完毕后,对于所有的 1≤i,j≤n,都一定有 f[i][j]≤f[n][n]。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
原卷作答说明:判断题正确填 A,错误填 B
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 30判断1.5 分
将第 18 行的
f[i][j] = std::max(f[i][j], std::max(f[i-1][j], f[i][j-1]));删去后,并不影响程序运行结果。( )
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 31单选3 分
输出的答案满足的性质有( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 32单选3 分
如果在 16 行的循环前加上以下两行:
std::sort(a+1, a+n+1); std::sort(b+1, b+n+1);则答案会( )。
整组作答后提交批改,成绩计入掌握度 · 已答 0/1
#include <algorithm>2#include <cstdio>3#include <cstring>4#define ll long long5int f[5007][5007];6int a[5007], b[5007];7int n;8int main() {9 scanf("%d", &n);10 for (int i = 1; i <= n; ++i) {11 scanf("%d", &a[i]);12 }13 for (int i = 1; i <= n; ++i) {14 scanf("%d", &b[i]);15 }16 for (int i = 1; i <= n; ++i) {17 for (int j = 1; j <= n; ++j) {18 f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));19 if (a[i] == b[j]) {20 f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);21 }22 }23 }24 printf("%d\n", f[n][n]);25 return 0;26}- 33单选3 分
如果输入的 a={1,2,…,n},而且 b 数组中数字均为 1∼n 中的正整数,则上述代码等价于下面哪个问题:( )。