[luoguP2254/NOI2005] 瑰丽华尔兹
sol
容易想到设 \(f_{T,i,j}\) 表示当时间为 \(T\),位置为 \(x,y\) 时的最大答案,时间复杂度 \(O(Tnm)\),无法接受。注意到输出中时间是分段的,而一段时间内的方向相同,即移动的范围时已知的,因此将第一维改为时间段 \(t\),但此时时间复杂度仍无本质改变。
由于四个方向的情况均较为类似,因此以方向 \(1\) 为例,设时间段长度为 \(len\),其转移方程为:
\[f_{t,i,j}=\max_{0 \le move \le len} f_{t-1,i+move,j} + move
\]
注意到这个方程不好优化,我们将移动步数转化为最终位置
\[f_{t,i,j} = \max_{i \le pos \le i + len} f_{t-1,pos, j} + pos - i
\]
\(i\) 可以视为常量,因此只需要维护一个滑动窗口的 \(f_{t-1,i,j}+i\) 的最小值即可,注意枚举的顺序。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 205;
int f[N][N][N];
int n, m, x, y, k;
char s[N][N];
int q[N];
int hh, tt;
int main(){
scanf("%d%d%d%d%d", &n, &m, &x, &y, &k);
for (int i = 1; i <= n; i ++ ) scanf("%s", s[i] + 1);
memset(f, -0x3f, sizeof f);
f[0][x][y] = 0;
for (int t = 1; t <= k; t ++ ) {
int st, ed, dir;
scanf("%d%d%d", &st, &ed, &dir);
int len = ed - st + 1;
if (dir == 1) {
for (int j = 1; j <= m; j ++ ){
hh = 0, tt = -1;
for (int i = n; i; i -- ) {
if (s[i][j] == 'x') {
hh = 0, tt = -1;
continue;
}
if (hh <= tt && i + len < q[hh]) hh ++ ;
while (hh <= tt && f[t - 1][q[tt]][j] + q[tt] <= f[t - 1][i][j] + i) tt -- ;
q[ ++ tt] = i;
f[t][i][j] = f[t - 1][q[hh]][j] + q[hh] - i;
}
}
}
else if (dir == 2) {
for (int j = 1; j <= m; j ++ ) {
hh = 0, tt = -1;
for (int i = 1; i <= n; i ++ ) {
if (s[i][j] == 'x') {
hh = 0, tt = -1;
continue;
}
if (hh <= tt && i - len > q[hh]) hh ++ ;
while (hh <= tt && f[t - 1][q[tt]][j] - q[tt] <= f[t - 1][i][j] - i) tt -- ;
q[ ++ tt] = i;
f[t][i][j] = f[t - 1][q[hh]][j] - q[hh] + i;
}
}
}
else if (dir == 3) {
for (int i = 1; i <= n; i ++ ) {
hh = 0, tt = -1;
for (int j = m; j; j -- ) {
if (s[i][j] == 'x') {
hh = 0, tt = -1;
continue;
}
if (hh <= tt && j + len < q[hh]) hh ++ ;
while (hh <= tt && f[t - 1][i][q[tt]] + q[tt] <= f[t - 1][i][j] + j) tt -- ;
q[ ++ tt] = j;
f[t][i][j] = f[t - 1][i][q[hh]] + q[hh] - j;
}
}
}
else if (dir == 4) {
for (int i = 1; i <= n; i ++ ) {
hh = 0, tt = -1;
for (int j = 1; j <= m; j ++ ) {
if (s[i][j] == 'x') {
hh = 0, tt = -1;
continue;
}
if (hh <= tt && j - len > q[hh]) hh ++ ;
while (hh <= tt && f[t - 1][i][q[tt]] - q[tt] <= f[t - 1][i][j] - j) tt -- ;
q[ ++ tt] = j;
f[t][i][j] = f[t - 1][i][q[hh]] - q[hh] + j;
}
}
}
}
int res = 0;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
res = max(res, f[k][i][j]);
printf("%d\n", res);
}

浙公网安备 33010602011771号