CF372C - Watching Fireworks is Fun

给定$m$个烟花发出时间$t_i$,$a_i$为烟花所在地。获得辛福的度$b_i-abs(a_i-x)$。每个单位时间最多移动$d$。
$n,d\leq 1.5\times 10^5,b_i\leq 10^9,m\leq 10^3$

选择$O(nm)$的算法。$dp[i][j]$表示第$i$个烟花的时候,在$j$个位位置。

  • 滚动数组减少内存
  • 发现后加入的元素$dp[k]$对于之前加入的$代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 2e5 + 10;
const int M = 3e2;
const int mod = 1e9 + 7;
ll dp[N], tmp[N];
int n, m, k, a[N], b[N], t[N];
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= m; i++)
scanf("%d%d%d", &a[i], &b[i], &t[i]);
t[0] = 1;
for (int i = 1; i <= m; i++)
{
ll gd = min(1ll * n, 1ll * (t[i] - t[i - 1]) * k);

deque<int> qu;
for (int j = 1; j <= n; j++)
tmp[j] = dp[j];
for (int t = 1, j = 1; t <= n; t++)
{
for (; j <= t + gd && j <= n; j++)
{
while (!qu.empty() && tmp[j] > tmp[qu.back()])
qu.pop_back();
qu.push_back(j);
}

while (!qu.empty() && qu.front() < t - gd)
qu.pop_front();
dp[t] = tmp[qu.front()] + b[i] - abs(a[i] - t);
}
}
ll ans = -1e18;
for (int i = 1; i <= n; i++)
ans = max(ans, dp[i]);
printf("%lld\n", ans);
}

</details>