对于允许最后一次操作溢出背包,在反向遍历(01背包变种),需要进行max(0, j-weight)限制

对于有额外操作的情况,最后不要降维,可能会因为重复访问引起错误,直接二维解决即可。

#include <algorithm>
#include <climits>
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
using ll =long long;

int main() {
    int n, m;
    cin >> n >> m;
    vector<pair<int, int>> coal(n);
    for (int i = 0; i < n; i++) cin >> coal[i].first >> coal[i].second;
    
    sort(coal.begin(), coal.end(), [](pair<int, int>& p1, pair<int, int>& p2) {
        return p1.first < p2.first;
    });
    ll minTime = INT_MAX;
    while ( !coal.empty() && coal.back().first * 2 >= m) {
        minTime = min(minTime, static_cast<ll>(coal.back().second / 2));
        coal.pop_back();
    }
    n = coal.size();
    if(n==0) {
        cout<<minTime;
        return 0;
    }
    vector<vector<ll>> dp(n+1,vector<ll>(m+1, INT_MAX)), magic(n+1,vector<ll>(m+1, INT_MAX));
    dp[0][0] = 0;
    magic[0][0] = 0;
    for (int i = 1; i <= n; i++) {
        int x = coal[i - 1].first;
        int y = coal[i - 1].second;
        dp[i]=dp[i-1];
        magic[i]=magic[i-1];
        for (int j = m; j >= 0; j--) {
            //no magic
            int k = max(0, j - x);
            if (dp[i-1][k] != INT_MAX) dp[i][j] = min(dp[i][j], dp[i-1][k] + y);
            if (magic[i-1][k] != INT_MAX) magic[i][j] = min(magic[i][j], magic[i-1][k] + y);
            //use magic
            k = max(0, j - 2 * x);
            if (dp[i-1][k] != INT_MAX) magic[i][j] = min(magic[i][j], dp[i-1][k] + y / 2);
            
        }
    }
    cout << min(magic[n][m], minTime);

//cout << magic[n][m];



}
// 64 位输出请用 printf("%lld")