6488. 【GDOI2020模拟02.29】土地勘测land

题目描述


题解

每次可以找一维折半,所以答案不超2log

反着做,变成每次把两个相邻的区间合并

枚举答案,维护f[i][j][k]表示当前第i行j~k列最多能向下到哪一行,g[i][j][k]表示列

每次先自己转移自己,然后考虑用另一个数组转移

比如对于当前的f[i][j][k],可以转到满足g[j][i][l]>=k的l(g已经转移过自己),画图理解

g同理

而当一个矩形包含另一个矩形时,被包含的矩形的操作次数必然不增,同理在某一条边界上缩一格时也不增

因此可以单调维护l

其中自己转移自己之后可以直接用回老数组,具体感性理解

关于转移顺序与时间: https://www.cnblogs.com/gmh77/p/12392514.html

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define file
using namespace std;

bool a[221][221];
int sum[221][221],f[222][221][221],g[222][221][221],n,m,i,j,k,l,ans;
char ch;

bool pd(int x1,int y1,int x2,int y2)
{
    int s=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
    return !s || s==(x2-x1+1)*(y2-y1+1);
}

void init()
{
    fo(j,1,m)
    {
        fo(k,j,m)
        {
            fo(i,1,n)
            {
                f[i][j][k]=max(f[i-1][j][k],i-1);
                while (f[i][j][k]<n && pd(i,j,f[i][j][k]+1,k))
                ++f[i][j][k];
            }
        }
    }
    fo(j,1,n)
    {
        fo(k,j,n)
        {
            fo(i,1,m)
            {
                g[i][j][k]=max(g[i-1][j][k],i-1);
                while (g[i][j][k]<m && pd(j,i,k,g[i][j][k]+1))
                ++g[i][j][k];
            }
        }
    }
}

int main()
{
    freopen("land.in","r",stdin);
    #ifdef file
    freopen("land.out","w",stdout);
    #endif
    
    scanf("%d%d",&n,&m);
    fo(i,1,n)
    {
        fo(j,1,m)
        {
            ch=getchar();
            while (ch!='.' && ch!='#')
            ch=getchar();
            
            a[i][j]=ch=='#';
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        }
    }
    
    fo(i,1,m){fo(j,i,m)f[n+1][i][j]=n;}
    fo(i,1,n){fo(j,i,n)g[m+1][i][j]=m;}
    
    init();
    
    while (!(f[1][1][m]==n || g[1][1][n]==m))
    {
        ++ans;
        
        fo(j,1,m)
        {
            fo(k,j,m)
            {
                l=0;
                fo(i,1,n)
                {
                    l=max(l,i-1);
                    while (l<n && g[g[j][i][l+1]+1][i][l+1]>=k)
                    ++l;
                    
                    f[i][j][k]=max(f[f[i][j][k]+1][j][k],l);
                }
            }
        }
        fo(j,1,n)
        {
            fo(k,j,n)
            {
                l=0;
                fo(i,1,m)
                {
                    l=max(l,i-1);
                    while (l<m && f[j][i][l+1]>=k)
                    ++l;
                    
                    g[i][j][k]=max(g[g[i][j][k]+1][j][k],l);
                }
            }
        }
    }
    printf("%d\n",ans);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12392822.html