【YBTOJ】【CodeForces 372C】Watching Fireworks is Fun
阿新 • • 發佈:2021-08-08
Watching Fireworks is Fun
連結:
題目大意:
一個城鎮有 \(n\) 個區域,從左到右 \(1\) 編號為 \(n\),每個區域之間距離 \(1\) 個單位距離。節日中有 \(m\) 個煙火要放,給定放的地點 \(a_i\),時間 \(t_i\),如果你當時在區域 \(x\),那麼你可以獲得 \(b_i - \vert a_i - x\vert\) 的開心值。你每個單位時間可以移動不超過 \(d\) 個單位距離。你的初始位置是任意的(初始時刻為 \(1\)),求你通過移動能獲取到的最大的開心值。
正文:
考慮 DP,設 \(f_{i,j}\) 表示當前放第 \(i\)
考慮到可以將 \(b_i\) 提出,得到:
\[f_{i,j}=\max_{k,|j-k|\leq(t_i-t_{i-1})d}\left\{f_{i-1,k}-|a_i-j|\right\} \]我們可以用單調佇列優化上面的式子。
最後答案為:
\[\sum_{i=1}^m b_i + \max_{i=1}^n\{f_{m,i}\} \]但是空間複雜度 \(\mathcal{O}(nm)\)
程式碼:
const int N = 150010, M = 310; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int n, m, d; ll f[2][N]; struct node { int a, t; }a[M]; deque <int> q; ll sum, ans = -(1ll << 60); int main() { n = Read(), m = Read(), d = Read(); for (int i = 1; i <= m; i++) a[i].a = Read(), sum += Read(), a[i].t = Read(); for (int i = 1; i <= m; i++) { ll len = (ll)(a[i].t - a[i - 1].t) * d; for (; !q.empty(); q.pop_back()); for (int j = 1; j <= n; j++) { for (; !q.empty() && q.front() < j - len; q.pop_front()); for (; !q.empty() && f[i & 1 ^ 1][j] > f[i & 1 ^ 1][q.back()]; q.pop_back()); q.push_back(j); f[i & 1][j] = f[i & 1 ^ 1][q.front()] - abs(a[i].a - j); } for (; !q.empty(); q.pop_back()); for (int j = n; j >= 1; j--) { for (; !q.empty() && q.front() > j + len; q.pop_front()); for (; !q.empty() && f[i & 1 ^ 1][j] > f[i & 1 ^ 1][q.back()]; q.pop_back()); q.push_back(j); f[i & 1][j] = max(f[i & 1][j], f[i & 1 ^ 1][q.front()] - abs(a[i].a - j)); } } for (int i = 1; i <= n; i++) ans = max(ans, f[m & 1][i]); ans = sum + ans; printf ("%lld", ans); return 0; }