传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1499
容易看出50分的dp方程:f[p][x][y] = max(f[p - 1][x][y], f[p - 1][x - dx][y - dy] + 1),但是对于满分数据就是TLE + MLE,然后我们发现数据范围强调了一个k <= 200,这提示我们可以将一段时间内相同方向的倾斜合并到一起做,就可以用单调队列优化了。。。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn = 210; int f[maxn][maxn][maxn]; bool z[maxn][maxn]; int n, m, x, y, k, ans; deque <int> q; void up(int p, int l) { for(int j = 1; j <= m; j ++) { while(!q.empty()) q.pop_back(); for(int i = n; i ; i --) { if(z[i][j]) { while(!q.empty()) q.pop_back(); continue; } while(!q.empty() && q.front() - i > l) q.pop_front(); if(f[p - 1][i][j] != -1) { while(!q.empty() && f[p - 1][q.back()][j] + q.back() < f[p - 1][i][j] + i) q.pop_back(); q.push_back(i); } if(!q.empty()) f[p][i][j] = f[p - 1][q.front()][j] + q.front() - i; } } return; } void down(int p, int l) { for(int j = 1; j <= m; j ++) { while(!q.empty()) q.pop_back(); for(int i = 1; i <= n; i ++) { if(z[i][j]) { while(!q.empty()) q.pop_back(); continue; } while(!q.empty() && i - q.front() > l) q.pop_front(); if(f[p - 1][i][j] != -1) { while(!q.empty() && f[p - 1][q.back()][j] - q.back() < f[p - 1][i][j] - i) q.pop_back(); q.push_back(i); } if(!q.empty()) f[p][i][j] = f[p - 1][q.front()][j] - q.front() + i; } } return; } void lt(int p, int l) { for(int i = 1; i <= n; i ++) { while(!q.empty()) q.pop_back(); for(int j = m; j ; j --) { if(z[i][j]) { while(!q.empty()) q.pop_back(); continue; } while(!q.empty() && q.front() - j > l) q.pop_front(); if(f[p - 1][i][j] != -1) { while(!q.empty() && f[p - 1][i][q.back()] + q.back() < f[p - 1][i][j] + j) q.pop_back(); q.push_back(j); } if(!q.empty()) f[p][i][j] = f[p - 1][i][q.front()] + q.front() - j; } } return; } void rt(int p, int l) { for(int i = 1; i <= n; i ++) { while(!q.empty()) q.pop_back(); for(int j = 1; j <= m; j ++) { if(z[i][j]) { while(!q.empty()) q.pop_back(); continue; } while(!q.empty() && j - q.front() > l) q.pop_front(); if(f[p - 1][i][j] != -1) { while(!q.empty() && f[p - 1][i][q.back()] - q.back() < f[p - 1][i][j] - j) q.pop_back(); q.push_back(j); } if(!q.empty()) f[p][i][j] = f[p - 1][i][q.front()] - q.front() + j; } } return; } void solve(int p, int d, int l) { if(d == 1) up(p, l); if(d == 2) down(p, l); if(d == 3) lt(p, l); if(d == 4) rt(p, l); return; } int main() { scanf("%d%d%d%d%d", &n, &m, &x, &y, &k); char c[maxn]; for(int i = 1; i <= n; i ++) { scanf("%s", c); for(int j = 1; j <= m; j ++) { if(c[j - 1] == 'x') z[i][j] = true; } } memset(f, -1, sizeof(f)); f[0][x][y] = 0; int d, s, t; for(int i = 1; i <= k; i ++) { scanf("%d%d%d", &s, &t, &d); solve(i, d, t - s + 1); } for(int i = 1; i <= n; i ++) { for(int j = 1; j <= m; j ++) { ans = max(ans, f[k][i][j]); } } printf("%d\n", ans); return 0; }