1 条题解

  • 0
    @ 2025-10-18 23:54:55

    解题思路 这道题的核心是通过放置床垫来阻止造反的连锁反应,从而使在时间 T 及以前造反的罪犯数量最少。关键在于理解床垫的作用:在牢房 i 和 i+1 之间放置床垫后,i 的造反不会影响 i+1 的原定造反时间。 我们可以使用动态规划来解决这个问题: 定义dp[i][j]表示考虑前 i 个牢房,使用 j 个床垫时,第 i 个牢房的造反时间 对于每个牢房 i 和床垫数量 j,有两种选择: 不在 i-1 和 i 之间放床垫:则 i 的造反时间是dp[i-1][j] + 1 在 i-1 和 i 之间放床垫:则 i 的造反时间是其原定时间t[i](需 j>0) 我们选择两种方案中较大的时间(这样能减少造反的可能性) 最后统计所有造反时间≤T 的牢房数量 C++ 代码实现 cpp 运行 #include <bits/stdc++.h> using namespace std;

    int main() { ios::sync_with_stdio(false); cin.tie(nullptr);

    int N, D, T;
    cin >> N >> D >> T;
    
    vector<int> t(N + 1);  // 1-based indexing
    for (int i = 1; i <= N; ++i) {
        cin >> t[i];
    }
    
    // dp[i][j]表示前i个牢房使用j个床垫时,第i个牢房的造反时间
    // 为节省空间,使用滚动数组
    vector<vector<int>> dp(2, vector<int>(D + 1));
    
    // 初始化第一个牢房
    dp[1][0] = t[1];
    for (int j = 1; j <= D; ++j) {
        dp[1][j] = t[1];  // 第一个牢房前不能放床垫,所以值不变
    }
    
    for (int i = 2; i <= N; ++i) {
        int curr = i % 2;
        int prev = 1 - curr;
        
        // 不使用新床垫
        dp[curr][0] = dp[prev][0] + 1;
        
        // 使用新床垫(j从1到D)
        for (int j = 1; j <= D; ++j) {
            // 两种选择:不在i-1和i间放床垫 或 放床垫
            dp[curr][j] = max(dp[prev][j] + 1, t[i]);
        }
    }
    
    // 统计造反时间<=T的牢房数量
    int last = N % 2;
    int count = 0;
    for (int i = 1; i <= N; ++i) {
        int curr = i % 2;
        if (dp[curr][D] <= T) {
            count++;
        }
    }
    
    cout << count << endl;
    
    return 0;
    

    } 代码解释 数据结构:使用滚动数组dp[2][D+1]来优化空间,因为计算第 i 个牢房时只需要第 i-1 个牢房的信息。 动态规划转移: 对于每个牢房 i 和床垫数量 j,我们选择两种方案中造反时间较晚的那个 这样做的目的是尽量让造反时间超过 T,从而减少造反的牢房数量 空间优化:通过滚动数组将空间复杂度从 O (N×D) 降低到 O (D),使其能处理 N=2×10^6 的情况 时间复杂度:O (N×D),其中 N 是牢房数量,D 是床垫数量 这个解法高效地计算出了在最优放置床垫的情况下,在时间 T 及以前造反的最少罪犯数量。

    • 1

    信息

    ID
    3143
    时间
    2000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    20
    已通过
    1
    上传者