2022-6-4 小明爱上课,切木头,最多分成多少块,躲猫猫,争渡

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 1n200,1LiRi104

输入

第一行一个整数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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值