CF480E - Parking Lot
Problem
给出一个
现在按顺序给出
Input
一行三个整数
.
为可选的点,X
为不可选的点。
Output
Sample
Input 1
7 8 4
........
X.....X.
........
........
.X......
........
........
1 5
6 4
3 5
4 6
Output 1
5
4
4
3
Solution
这种有后效性的题目有一个固定的套路,可以叫操作反过来,即将一个不可选的点变成一个可以选择的点。
不难看出这样的答案单调不降,且如果答案增加一定是由一个点的状态改变导致的。同时答案的取值较小,于是问题转化为每当一个点被更改状态后,不断判断答案能否增加
那该如何判断?我们将
最后的结果倒叙记录,正序输出。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <deque>
using namespace std;
using Pii = pair<int, int>;
const int kmax = 2005;
int n, m, k;
Pii q[kmax];
int a[kmax][kmax], s[kmax][kmax];
int l[kmax][kmax], r[kmax][kmax];
int res, ress[kmax];
char ch;
bool Check(int mid) {
for(int i = 1, _i = mid; _i <= n; i++, _i++) {
for(int j = 1, _j = mid; _j <= m; j++, _j++) {
if(s[_i][_j] - s[i - 1][_j] - s[_i][j - 1] + s[i - 1][j - 1] == 0) return 1;
}
}
return 0;
}
int Calc() { // 二分求初始答案
int l = 1, r = min(n, m);
for(int mid; l <= r;) {
mid = (l + r) >> 1;
if(Check(mid)) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return l - 1;
}
bool Solve(int k, int j) {
deque<int> q[2];
for(int i = 1; i <= n; i++) { // 枚举正方形的下底
for(; !q[0].empty() && q[0].front() < i - k + 1; q[0].pop_front()) { // 不在矩阵内
}
for(; !q[1].empty() && q[1].front() < i - k + 1; q[1].pop_front()) {
}
for(; !q[0].empty() && l[q[0].back()][j] >= l[i][j]; q[0].pop_back()) { // 拓展的比当前行远的要弹出
}
for(; !q[1].empty() && r[q[1].back()][j] >= r[i][j]; q[1].pop_back()) {
}
q[0].push_back(i), q[1].push_back(i);
if(i < k) continue; // 正方形长度不够
if(l[q[0].front()][j] + r[q[1].front()][j] - 1 >= k) return 1;
}
return 0;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cin >> ch;
a[i][j] = ch == 'X';
}
}
for(int i = 1; i <= k; i++) {
cin >> q[i].first >> q[i].second;
a[q[i].first][q[i].second] = 1; // 先标记
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
l[i][j] = (a[i][j] ? 0 : l[i][j - 1] + 1); // 这里的计算包括原点
}
for(int j = m; j; j--) {
r[i][j] = (a[i][j] ? 0 : r[i][j + 1] + 1);
}
}
res = Calc(); // 计算初始答案
for(int i = k; i; i--) { // 倒叙计算
a[q[i].first][q[i].second] = 0; // 还原标记
ress[i] = res;
for(int j = 1; j <= m; j++) {
l[q[i].first][j] = (a[q[i].first][j] ? 0 : l[q[i].first][j - 1] + 1);
}
for(int j = m; j; j--) {
r[q[i].first][j] = (a[q[i].first][j] ? 0 : r[q[i].first][j + 1] + 1);
}
for(; Solve(res + 1, q[i].second); res++) { // 判断答案能否增加
}
}
for(int i = 1; i <= k; i++) { // 正序输出
cout << ress[i] << '\n';
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效