原题传送门
首先还是暴力dp
表示时间
,位置
的答案
复杂度是 ,可以拿到50分的好成绩
转换思路
表示第
个时间段,最终位置在
的答案
枚举上一个时间段的最终位置
,因为两个时间段的位置一定共线,所以这一个枚举只需要
复杂度是
还是不行,考虑把枚举上一个时间段最终位置的循环用单调队列优化掉
时间变成了
可以过了
顺便把
数组的第一维滚动掉,这样空间也满足要求了
Code:
#include <bits/stdc++.h>
#define maxn 210
using namespace std;
int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
struct node{
int sum, pos;
}q[maxn];
int n, m, X, Y, k, dp[maxn][maxn], ans;
char s[maxn][maxn];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
void DP(int x, int y, int l, int d){
int h = 1, t = 0;
for (int i = 1; x && y && x <= n && y <= m; ++i, x += dx[d], y += dy[d])
if (s[x][y] == 'x') h = 1, t = 0;
else{
while (h <= t && q[t].sum + i - q[t].pos <= dp[x][y]) --t;
q[++t] = (node){dp[x][y], i};
while (h <= t && i - q[h].pos > l) ++h;
if (h <= t) ans = max(ans, dp[x][y] = q[h].sum + i - q[h].pos);
}
}
int main(){
n = read(), m = read(), X = read(), Y = read(), k = read();
for (int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= m; ++j) dp[i][j] = -1e9;
dp[X][Y] = 0;
while (k--){
int s = read(), t = read(), d = read(), l = t - s + 1;
if (d == 1) for (int i = 1; i <= m; ++i) DP(n, i, l, d);
if (d == 2) for (int i = 1; i <= m; ++i) DP(1, i, l, d);
if (d == 3) for (int i = 1; i <= n; ++i) DP(i, m, l, d);
if (d == 4) for (int i = 1; i <= n; ++i) DP(i, 1, l, d);
}
printf("%d\n", ans);
return 0;
}