1341E - Nastya and Unexpected Guest

给$m$个安全点, 从$0$走到$n$,$g$秒绿灯$r$秒红灯循环,绿灯可以走,在安全点可以转向,绿灯必须移动,红灯必须呆在安全点。问最少时间达到$n$需要的的时间。

$dp[i][j]$表示到达$i$这个点耗时$dp[i][j]\times (g+r)+j$秒。

最后是找到达$n$的各种$dp[][j]$的最小值。

考虑$BFS$去找(类似最短路),假设当前在$x$点,

  • 若$j+a[x+1]-a[x],j+a[x]-a[x-1]<g$则表示可以走,并且转移$dp$权值不会增加。
  • 若$j+a[x+1]-a[x],j+a[x]-a[x-1]=g$则表示可以走,但一轮就结束了。转移$dp$权值会增加。
  • 进行转移可以进行类似最短路的放缩变换。
    类似与$01BFS$,边权有01,双端队列优化即可,否则$TLE \ on \ 80$。
代码
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 1e4 + 100;
const int mod = 1e9 + 7;
const int M = 1e3 + 100;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}
ll dp[N][M];
int n, m, g, r, a[N];
int main()
{
n = read(), m = read();

for (int i = 1; i <= m; i++)
a[i] = read();

g = read(), r = read();
for (int i = 1; i <= m; i++)
for (int j = 0; j <= g; j++)
dp[i][j] = 1e18;
sort(1 + a, 1 + a + m);
dp[1][0] = 0;
deque<pii> q;
ll ans = 1e18;
q.push_back(mk(1, 0));
while (!q.empty())
{
pii p = q.front();
q.pop_front();
int x = p.first;
int y = p.second;
if (y == 0 && g >= n - a[x])
{
ans = min(ans, dp[x][y] * (g + r) + n - a[x]);
}
//cout << x << " " << y << " " << dp[x][y] << endl;
if (x == m)
continue;
else
{
if (y + a[x + 1] - a[x] < g && dp[x + 1][y + a[x + 1] - a[x]] > dp[x][y])
dp[x + 1][y + a[x + 1] - a[x]] = dp[x][y], q.push_front(mk(x + 1, y + a[x + 1] - a[x]));
else if (y + a[x + 1] - a[x] == g && dp[x][y] + 1 < dp[x + 1][0])
dp[x + 1][0] = dp[x][y] + 1, q.push_back(mk(x + 1, 0));
}
if (x == 1)
continue;
else
{
//cout << x << " " << y << "--" << dp[x][y] << endl;
if (y + a[x] - a[x - 1] < g && dp[x - 1][y + a[x] - a[x - 1]] > dp[x][y])
dp[x - 1][y + a[x] - a[x - 1]] = dp[x][y], q.push_front(mk(x - 1, y + a[x] - a[x - 1]));
else if (y + a[x] - a[x - 1] == g && dp[x][y] + 1 < dp[x - 1][0])
dp[x - 1][0] = dp[x][y] + 1, q.push_back(mk(x - 1, 0));
}
}

if (ans == 1e18)
printf("-1");
else
printf("%lld", ans);
}