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

浙公网安备 33010602011771号