码迷,mamicode.com
首页 > 其他好文 > 详细

并不对劲的CF480E:Parking Lot

时间:2019-10-07 19:40:03      阅读:72      评论:0      收藏:0      [点我收藏+]

标签:ios   代码   长度   ring   for   etc   有一个   mes   而且   

题目大意

有一个\(n\times m\)的网格,每个位置是黑色或者白色。\(k\)个操作,每个操作是将一个白格子染黑,操作后输出当前最大的白色正方形的边长。\(n,m,k\leq 2\times 10^3\)

题解

发现在每次操作是把白格子变黑,会使答案变小。维护“变小的最大值”听上去不太舒服。考虑把操作全都反过来,变成把黑格子染白。
这样每次操作之后,如果答案变大了,那么新的答案正方形一定包含在被操作的格子。
考虑对每个点记它左边最左的白格子和右边最右的白格子,操作时暴力更新与被操作点同行的点。
答案就是想找连续的一段与被操作的点在同一列,“段的长度”与“最左的右边界-最右的左边界”的最小值尽可能大。
发现可以判断答案是否大于一个数\(x\):当这一列上存在一个点,满足该点到从该点往上数第\(x\)个点满足“最左的右边界-最右的左边界”不少于\(x\)\(x\)就可以;反之就不可以。
可以用线段树或单调队列维护区间最左右边界和最右左边界。
这题知道判断解是否合法的方法后也不用二分,因为在处理过后答案就是不降的,而且不会超过\(min(n,m)\),而判断能否使答案增加1需要\(\Theta(n)\)\(\Theta(n\space log\space n)\)的时间复杂度,所以可以每次暴力判断能否使答案增加。
总时间复杂度\(\Theta(n\times m+k\times m+k\times n)\)

代码

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 2007
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}
void write(int x)
{
    char ch[20];int f=0;
    if(!x){putchar('0'),putchar('\n');return;}
    if(x<0)putchar('-'),x=-x;
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
}
int qx[maxn],qy[maxn],q[maxn],hd,tl; 
int col[maxn][maxn],ans,lmx[maxn][maxn],rmx[maxn][maxn],n,m,k,res[maxn],tmp[maxn],dp[maxn][maxn];
char s[maxn];
int jud(int yy)
{
    hd=1,tl=0;
    rep(i,1,n)
    {
        while(hd<=tl&&q[hd]<i-(ans+1)+1)hd++;
        while(hd<=tl&&lmx[q[tl]][yy]<=lmx[i][yy])tl--;
        q[++tl]=i;
        if(i<ans+1)continue;
        tmp[i]=yy-lmx[q[hd]][yy]+1;
    }
    hd=1,tl=0;
    rep(i,1,n)
    {
        while(hd<=tl&&q[hd]<i-(ans+1)+1)hd++;
        while(hd<=tl&&rmx[q[tl]][yy]>=rmx[i][yy])tl--;
        q[++tl]=i;
        if(i<ans+1)continue;
        tmp[i]+=rmx[q[hd]][yy]-yy;
    }
    rep(i,ans+1,n)if(tmp[i]>=ans+1)return 1;
    return 0; 
}
int main()
{
    n=read(),m=read(),k=read();
    rep(i,1,n)
    {
        scanf("%s",s+1);
        rep(j,1,m)if(s[j]!='.')col[i][j]=1; 
    }
    rep(i,1,k)qx[i]=read(),qy[i]=read(),col[qx[i]][qy[i]]=1;
    rep(i,1,n)
    {
        rep(j,1,m)
        {
            if(col[i][j]){lmx[i][j]=j+1;continue;}
            dp[i][j]=min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
            ans=max(dp[i][j],ans);
            if(j==1||col[i][j-1])lmx[i][j]=j;
            else lmx[i][j]=lmx[i][j-1];
        }
        dwn(j,m,1)
        {
            if(col[i][j]){rmx[i][j]=j-1;continue;}
            if(j==m||col[i][j+1])rmx[i][j]=j;
            else rmx[i][j]=rmx[i][j+1];
        }
    }
    dwn(i,k,1)
    {
        res[i]=ans;
        col[qx[i]][qy[i]]=0;
        int nl=qy[i],nr=qy[i];
        while(nl-1>=1&&!col[qx[i]][nl-1])nl--;
        while(nr+1<=m&&!col[qx[i]][nr+1])nr++;
        rep(j,nl,nr)lmx[qx[i]][j]=nl,rmx[qx[i]][j]=nr;
        
        while(jud(qy[i]))ans++;
    }
    rep(i,1,k)write(res[i]);
    return (0-0);
}

并不对劲的CF480E:Parking Lot

标签:ios   代码   长度   ring   for   etc   有一个   mes   而且   

原文地址:https://www.cnblogs.com/xzyf/p/11631689.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!