\(dp\) + 单调队列优化
\(dp[k][i][j]\) 表示在第 \(k\) 次倾斜后 \(x = i\) 且 \(y = j\) 的位置上,能够滑动的最长距离,第一纬可以直接用滚动数组消除
显然每次倾斜都要对所有的状态进行更新,分四个方向进行更新,以向右滑动为例,有状态转移方程:
\[dp[i][j] = \max_{k=t-j}^{j}(dp[i][k]+j-k) \]\(t\) 表示这次倾斜持续的时长
使用这样的转移,算法时间复杂度为 \(O(Tn^3)\),显然不是我们能接受的
考虑相同方向,相邻的位置都是从几乎重叠的区间转移过来,且满足单调,因此考虑是用单调队列来进行优化
\[dp[i][j] = \max_{k=t-j}^{j}(dp[i][k]-k) + j \]优化后,算法时间复杂度为 \(O(Tn^2)\)
#include <iostream> #include <cstdio> #include <stack> #include <deque> #include <string> using namespace std; #define pii pair<int, int> const int maxn = 210; const int inf = 0x3fffffff; string s[maxn]; int dp[maxn][maxn]; int main() { int n, m, x, y, k; cin >> n >> m >> x >> y >> k; for(int i=0; i<n; i++) cin >> s[i]; for(int i=0; i<=n; i++) for(int j=0; j<=m; j++) dp[i][j] = -inf; x--; y--; dp[x][y] = 0; while(k--) { int a, b, op; cin >> a >> b >> op; int t = b - a + 1; if(op == 1) { for(int j=0; j<m; j++) { deque<pii>q; for(int i=n-1; i>=0; i--) { if(s[i][j] == 'x') while(q.size()) q.pop_front(); while(q.size() && q.back().first <= dp[i][j] - n + i) q.pop_back(); q.push_back({dp[i][j] - n + i, i}); while(q.front().second > i + t) q.pop_front(); dp[i][j] = q.front().first + n - i; } } } else if(op == 2) { for(int j=0; j<m; j++) { deque<pii>q; for(int i=0; i<n; i++) { if(s[i][j] == 'x') while(q.size()) q.pop_front(); while(q.size() && q.back().first <= dp[i][j] - i) q.pop_back(); q.push_back({dp[i][j] - i, i}); while(q.front().second < i - t) q.pop_front(); dp[i][j] = q.front().first + i; } } } else if(op == 3) { for(int i=0; i<n; i++) { deque<pii>q; for(int j=m-1; j>=0; j--) { if(s[i][j] == 'x') while(q.size()) q.pop_front(); while(q.size() && q.back().first <= dp[i][j] - m + j) q.pop_back(); q.push_back({dp[i][j] - m + j, j}); while(q.front().second > j + t) q.pop_front(); dp[i][j] = q.front().first + m - j; } } } else if(op == 4) { for(int i=0; i<n; i++) { deque<pii>q; for(int j=0; j<m; j++) { if(s[i][j] == 'x') while(q.size()) q.pop_front(); while(q.size() && q.back().first <= dp[i][j] - j) q.pop_back(); q.push_back({dp[i][j] - j, j}); while(q.front().second < j - t) q.pop_front(); dp[i][j] = q.front().first + j; } } } } int ans = -inf; for(int i=0; i<n; i++) for(int j=0; j<m; j++) ans = max(ans, dp[i][j]); cout << ans << endl; return 0; }