题面

动态加障碍物,同时查询最大子正方形。

n,m≤2000n,m\leq2000n,m≤2000

题解

加障碍不好做,直接离线后反着做,每次就是清除一个障碍物。

显然倒着做答案是递增的,而且答案的值域是[0,min⁡(n,m)][0,\min(n,m)][0,min(n,m)],所以我们可以存一下答案,然后每次checkcheckcheck能不能+1+1+1。

考虑把一个位置的障碍物清除后如果答案能变大,这个矩阵一定包含这个位置。那么考虑怎么求是否存在一个边长为lenlenlen的矩形覆盖这个位置。

我们存下l[i][j]l[i][j]l[i][j]和r[i][j]r[i][j]r[i][j],表示(i,j)(i,j)(i,j)位置向左和向右最多能扩展的距离。这个东西是可以维护的,因为每次改一个点只会影响一行mmm个数的值。直接暴力修改。

然后对于(i,j)(i,j)(i,j)位置,如果存在一个边长为lenlenlen的正方形覆盖(i,j)(i,j)(i,j),一定在第jjj列存在连续lenlenlen行满足:

min⁡(l[k][j])+min⁡(r[k][j])−1≥len\min(l[k][j])+\min(r[k][j])-1\geq lenmin(l[k][j])+min(r[k][j])−1≥len

这样我们就可以直接two-pointers,两个单调队列维护lll和rrr的最小值来判断是否存在答案。

我的代码中并没有保证一定经过(i,j)(i,j)(i,j)这个点,但是这样并不会错过答案。

时间复杂度O(nm)O(nm)O(nm)

CODE

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2005;
int n, m, k, l[MAXN][MAXN], r[MAXN][MAXN];
char S[MAXN];
int a[MAXN][MAXN], dp[MAXN][MAXN], x[MAXN], y[MAXN], ans[MAXN];
void clr(int 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 >= 1; --j) r[i][j] = a[i][j] ? 0 : r[i][j+1] + 1;
}
int solve() {
int re = 0;
for(int i = 1; i <= n; ++i) clr(i);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
if(!a[i][j]) {
dp[i][j] = min(min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1]) + 1;
re = max(re, dp[i][j]);
}
return re;
} int v[2][MAXN], q[2][MAXN], s[2], t[2];
inline void del(int p) {
while(s[0] < t[0] && q[0][s[0]] <= p) ++s[0];
while(s[1] < t[1] && q[1][s[1]] <= p) ++s[1];
}
inline void ins(int i) {
while(s[0] < t[0] && v[0][q[0][t[0]-1]] >= v[0][i]) --t[0]; q[0][t[0]++] = i;
while(s[1] < t[1] && v[1][q[1][t[1]-1]] >= v[1][i]) --t[1]; q[1][t[1]++] = i;
}
bool calc(int j, int len) {
for(int i = 1; i <= n; ++i) v[0][i] = l[i][j], v[1][i] = r[i][j];
s[0] = s[1] = t[0] = t[1] = 0;
q[0][0] = q[1][0] = 0;
for(int i = 1, p = 0; i <= n; ++i) {
while(i-p >= len) del(p++); ins(i);
if(i >= len && v[0][q[0][s[0]]] + v[1][q[1][s[1]]] - 1 >= len) return 1;
}
return 0;
}
int main () {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; ++i) {
scanf("%s", S+1);
for(int j = 1; j <= m; ++j)
a[i][j] = S[j] == 'X';
}
for(int i = 1; i <= k; ++i) scanf("%d%d", &x[i], &y[i]), a[x[i]][y[i]] = 1;
ans[k] = solve();
for(int i = k; i > 1; --i) {
a[x[i]][y[i]] = 0;
clr(x[i]);
for(ans[i-1]=ans[i]; calc(y[i], ans[i-1]+1); ++ans[i-1]);
}
for(int i = 1; i <= k; ++i) printf("%d\n", ans[i]);
}

CF480E Parking Lot(two-pointers + 单调队列优化)的更多相关文章

  1. BestCoder Round #89 02单调队列优化dp

    1.BestCoder Round #89 2.总结:4个题,只能做A.B,全都靠hack上分.. 01  HDU 5944   水 1.题意:一个字符串,求有多少组字符y,r,x的下标能组成等比数列 ...

  2. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  3. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  4. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  5. UESTC 880 生日礼物 --单调队列优化DP

    定义dp[i][j]表示第i天手中有j股股票时,获得的最多钱数. 转移方程有: 1.当天不买也不卖: dp[i][j]=dp[i-1][j]; 2.当天买了j-k股: dp[i][j]=max(dp[ ...

  6. poj 1821 Fence 单调队列优化dp

    /* poj 1821 n*n*m 暴力*/ #include<iostream> #include<cstdio> #include<cstring> #incl ...

  7. 使用单调队列优化的 O(nm) 多重背包算法

    我搜索了一下,找到了一篇很好的博客,讲的挺详细:链接. 解析 多重背包的最原始的状态转移方程: 令 c[i] = min(num[i], j / v[i]) f[i][j] = max(f[i-1][ ...

  8. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

  9. uvalive4327(单调队列优化)

    这题我有闪过是用单调队列优化的想法,也想过有左右两边各烧一遍. 但是不敢确定,搜了题解,发现真的是用单调队列,然后写了好久,调了好久下标应该怎么变化才过的. dp[i][j] 表示走到第i行,第j个竖 ...

随机推荐

  1. jenkins【目录】:目录

    jenkins[目录]:目录 GitLab 自动触发 Jenkins 构建 返回

  2. LeetCode 144. 二叉树的前序遍历(Binary Tree Preorder Traversal)

    144. 二叉树的前序遍历 144. Binary Tree Preorder Traversal 题目描述 给定一个二叉树,返回它的 前序 遍历. LeetCode144. Binary Tree ...

  3. jdbc连接oracle的三种方法

    jdbc连接oracle的三种方法 使用service_name,配置方式:jdbc:oracle:thin:@//<host>:<port>/<service_name ...

  4. 【Qt开发】第一个Qt程序Hello World!

    一:说在前头 我的第一份工作是做生产工具,当时用的MFC,IDE是VC6.0,现在想想真是古董级别,10年至今,微软也一直没有对MFC进行升级,冥冥中感觉微软自己都放弃MFC了,市场上貌似MFC的岗位 ...

  5. Python-21-socket编程

    一.基础知识 1. C/S架构 C/S架构即客户机/服务器模式. 它可以分为客户机和服务器两层: 第一层:  在客户机系统上结合了界面显示与业务逻辑: 第二层:  通过网络结合了数据库服务器. 简单的 ...

  6. Python进阶:metaclass谈

    metaclass 的超越变形特性有什么用? 来看yaml的实例: import yaml class Monster(yaml.YAMLObject): yaml_tag = u'!Monster' ...

  7. S04_CH02_工程移植ubuntu并一键制作启动盘

    S04_CH02_工程移植ubuntu并一键制作启动盘 2.1概述 2.2搭建硬件系统 本章硬件工程还是使用<S04_CH01_搭建工程移植LINUX/测试EMMC/VGA>所搭建的VIV ...

  8. Springboot模板(thymeleaf、freemarker模板)

    目的: 1.thymeleaf模板 2.Freemarker模板 thymeleaf模板 thymeleaf 的优点: 支持html5标准,页面无须部署到servlet开发到服务器上,直接通过浏览器就 ...

  9. FFMPEG - ffplay源代码分析

    FFmpeg是一个开源,免费,跨平台的视频和音频流方案,它提供了一套完整的录制.转换以及流化音视频的解决方案.而ffplay是有ffmpeg官方提供的一个基于ffmpeg的简单播放器.学习ffplay ...

  10. 基于re模块的计算器

    最终计算器需求: 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - ...