1. 小明爱上课 [动态规划]
小明非常喜欢上课,现在小明的课表有一些课,他可以通过课表选择上哪些课。
上课会有奖励,每门课上课时间长短不同奖励也会不一样,存在上课时间更长,奖励更少的情况。每一门课上课的总时长为整数。不同时长的奖励,题目数据中会给出。
对于每一门课,小明只可以上一次,现在小明一共有m分钟的时间可以安排上课,但是小明想要得到最大的奖励,聪明的你可以帮助小明解决这个问题吗?
输入
第一行,输入两个数n和m,表示课程的数目以及小明需要上课的时间 接下来包括n行,每行m个数,第i个数表示对于每门课上i分钟的奖励 (i从1开始,每门课程只可以上一次)
对于10%的数据,1<= n<= 4,1<=m<=4
对于50%的数据,1<= n<= 100,1<=m<=100
对于100%的数据,1<= n<=100,1<=m<=100
1<=奖励值<=1000
输出
输出一个数,表示最大的奖励值。
输入样例
2 3
3 2 1
3 2 1
输出样例
6
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, dp[105][105], credit[105][105];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
cin >> credit[i][j];
for (int i = 1; i <= n; ++i) { // 课程 i
for (int s = 1; s <= m; ++s) {
dp[i][s] = dp[i - 1][s]; // 不上课程 i
for (int j = 1; j <= s; ++j) {
dp[i][s] = max(dp[i][s], credit[i][j] + dp[i - 1][s - j]);
}
}
}
cout << dp[n][m];
return 0;
}
2. 切木头 [二分]
有n
个木棍,长度不等,现在要将他们切成同等长度的木棍m
个,并且每段的长度都为整数。问这m根木棍最长能有多长?
如果分不出来,输出0
。
输入
第一行2个数:n, m中间用空格分隔(1 <= n <= 100000, 1 <= m <= 10^9)
后面n行:每行1个数,对应木棍的长度(1 <= Li <= 10^9)。
输出
输出一个整数,对应木棍的长度。
输入样例
3 10
15
25
12
输出样例
5
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, nums[100005];
bool check(int x) {
int ans = 0;
for (int i = 0; i < n; ++i) ans += (nums[i] / x);
return ans >= m;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> nums[i];
int lo = 1, hi = 1000000005;
while (lo < hi) {
int mi = lo + ((hi - lo) >> 1);
check(mi) ? lo = mi + 1 : hi = mi;
}
cout << --lo;
return 0;
}
3. 最多分成多少块 [贪心]
小b有个长度为n的数组a,她想将这个数组排序。
然而小b很懒,她觉得对整个数组排序太累了,因此她请你将a分成一些块,使得她只需要对每一块分别排序,就能将整个数组排序。
请问你最多能把a分成多少块。
保证a为0…n-1的一个排列。
样例解释:
将a分成2块或者更多块,都无法得到所需的结果。
例如,分成 [4, 3], [2, 1, 0] ,排序得到的结果是 [3, 4, 0, 1, 2],这不是有序的数组。
输入
第一行一个数n;
第二行n个数表示a[i],以空格隔开。
n<=10
输出
输出一个数表示划分块的数量
输入样例
5
4 3 2 1 0
输出样例
5
代码
#include<bits/stdc++.h>
using namespace std;
int n, nums[100005];
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> nums[i];
int ans = 0;
for (int i = 0, maxNumber = -1; i < n; ++i) {
maxNumber = max(maxNumber, nums[i]);
if (maxNumber == i) ans++;
}
cout << ans;
return 0;
}
4. 躲猫猫 [DFS]
在一个8*8
的二维平面内,你初始时刻处于M
点,每一个移动轮次你可以向8联通的方向走1
格,也可以呆在原地保持不动。你需要移动到逃生点A
,并且安全待到你的下一移动轮次才能逃生。
方格内还有很多猫,用S
表示。每一移动轮次你先移动,在你移动结束后,所有的猫都会同时向下移动一格(在二维平面最下方一行时,如果猫向下移动视为移出平面,不再出现)。所有猫移动完成之后,视为结束这一移动轮次。
问最终你能否从M
点移动到A
点逃生。可以的话输出Win
,否则输出Lost
。
输入
输入共8行,每行的字符包括'A' 'M' 'S' '.',其中M表示起始位置,A表示终点位置,S表示猫,.表示空地,可以随便走。
输出
输出共1行,如果可以从M点移动到A点。输出Win,否则输出Lost。
输入样例
.......A
........
........
........
........
........
SS......
M.......
输出样例
Lost
代码
#include<bits/stdc++.h>
using namespace std;
const vector<pair<int, int>> DIR{{0, 0}, {0, 1}, {0, -1}, {1, 0}, {-1, 0},
{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int xt, yt;
bool isCat[8][8];
bool dfs(int xi, int yi, int time) {
if (xi < 0 || yi < 0 || xi == 8 || yi == 8) return false; // 边界判断
if (time > 0 && xi - time + 1 > 0 && isCat[xi - time + 1][yi]) return false; // 被猫捕获(前序状态)
if (xi - time > 0 && isCat[xi - time][yi]) return false; // 被猫捕获(当前状态)
if ((xi == xt && yi == yt) || time == 8) return true; // 所有猫均移除边界, 总有一条路径到达终点
return any_of(DIR.begin(), DIR.end(), [&](const pair<int, int> dir) {
return dfs(xi + dir.first, yi + dir.second, time + 1);
});
}
int main() {
int xi, yi;
string s;
for (int i = 0; i < 8; ++i) {
cin >> s;
for (int j = 0; j < 8; ++j) {
switch (s[j]) { // 太久没用过 switch 了, 心血来潮用一下
case 'S': isCat[i][j] = true; break;
case 'M': xi = i, yi = j; break;
case 'A': xt = i, yt = j; break;
}
}
}
cout << (dfs(xi, yi, 0) ? "Win" : "Lost");
return 0;
}
5. 争渡 [动态规划]
人生如逆水行舟,不进则退。你一生中有
n
n
n个阶段,每个阶段有一个状态下限
L
i
L_i
Li,也有一个状态上限
R
i
R_i
Ri,你想规划你的一生中各阶段的状态值,使得你的状态在
n
n
n个阶段中始终在变好(严格递增)。请你计算有多少种不同的人生规划。由于答案较大,只需输出答案对998244353998244353
取余的结果
数据范围: 1 ≤ n ≤ 200 , 1 ≤ L i ≤ R i ≤ 104 1≤n≤200,1≤L_i≤R_i≤104 1≤n≤200,1≤Li≤Ri≤104
输入
第一行一个整数n,表示人生的阶段数。
接下来n行,每行两个整数Li, Ri,表示这个阶段的状态值的下限和上限。
输出
输出仅一行,表示方案数mod 998244353的结果。
输入样例
4
1 6
3 5
1 4
4 6
输出样例
4
代码
#include<bits/stdc++.h>
using namespace std;
using ull = unsigned long long;
ull dp[205][10005];
int lim[205][2];
int main() {
auto &lim_ = lim;
auto &dp_ = dp;
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> lim[i][0] >> lim[i][1];
dp[0][0] = 1ll; // 边界条件
for (int i = 1, L, R; i <= n; ++i) {
L = lim[i][0], R = lim[i][1];
ull sum = 0;
for (int j = 0; j < L; ++j) sum += dp[i - 1][j] % 998244353;
for (int j = L; j <= R; ++j) {
dp[i][j] = sum;
sum += dp[i - 1][j] % 998244353;
}
}
ull ans = 0;
for (int j = lim[n][0]; j <= lim[n][1]; ++j) {
ans += dp[n][j] % 998244353;
}
cout << ans % 998244353;
return 0;
}
题单来源:QQ群200162761
。