Loading

P6715 [CCO 2018] Fun Palace

我对 DP,完全没有理解呢……

首先,要通过的话是要有人看门的,如果当前人数 \(\ge a_i + b_i\),那么 \(i\) 这扇门就没有意义,因为可以随便来回。然后因为可以又来又回,所以需要除掉后效性。怎么去呢,我们发现为了往前爆破,如果现在过不去,肯定要把后面的门打开,解救后面的人,然后聚集起来一路向前。如果从前往后考虑每个点放多少个人,那么就需要保证后面不会有更多的人过来,即一个点上的人数只由其原本人数和前面的人数决定,这样就没有后效性了,且可以保证不会被爆破到起点。然后就是考虑 \(f_{i, j}\) 表示前 \(i\) 扇门,第 \(i\) 扇门聚集了 \(j\) 个人的答案,转移显然,时间复杂度 \(\mathcal{O}(n^2)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 1e3 + 10, M = 1e4 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
    cout << arg << ' ';
    dbg(args...);
}
namespace Loop1st {
int n, m, e, a[N], b[N], f[N][M << 1];
void cmax(int &x, int y) { if (x < y) x = y; }
void main() {
    cin >> n >> e; m = e;
    for (int i = 1; i < n; i++) cin >> a[i] >> b[i], m = max(m, a[i] + b[i]);
    for (int i = 0; i < e; i++) f[0][i] = i;
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (j < a[i]) cmax(f[i][j + b[i]], f[i - 1][j] + b[i]);
            else if (j < a[i] + b[i]) cmax(f[i][j - a[i]], f[i - 1][j]);
            else cmax(f[i][j], f[i - 1][j]);
        }
        int mx = 0;
        for (int j = 0; j < a[i]; j++) cmax(mx, f[i - 1][j]);
        for (int j = 0; j < b[i]; j++) cmax(f[i][j], mx + j); 
    }
    int ans = 0;
    for (int i = 0; i < m; i++) cmax(ans, f[n - 1][i]);
    cout << ans << '\n';
}

}
int main() {
    // freopen("data.in", "r", stdin);
    // freopen("data.out", "w", stdout);
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T = 1;
    // cin >> T;
    while (T--) Loop1st::main();
    return 0;
}
// start coding at 19:45
// finish debugging at 19:52
posted @ 2026-01-11 20:15  循环一号  阅读(2)  评论(0)    收藏  举报