Codeforces 1301E - Nanosoft(二维RMQ+二分)

题意

给一个 n ∗ m n*m nm的矩形,每个格子有一个颜色。总共4种颜色。
一个合法的正方体是由左上四分之一为颜色1,右上四分之一为颜色2,左下四分之一为颜色3,右下四分之一为颜色4构成。
Q Q Q次查询,每次查询子矩阵 ( x 1 , y 1 , x 2 , y 2 ) (x1,y1,x2,y2) (x1,y1,x2,y2)中最大的合法正方体面积。如果不存在,输出0.
n , m ≤ 500 , q ≤ 3 e 5 n,m\le 500, q\le 3e5 n,m500,q3e5

解题思路

先对于每个点,二分求出以这个点为合法正方形左上部分的右下角可以获得的最大合法正方体大小。复杂度 O ( n m l o g ( n ) ) O(nmlog(n)) O(nmlog(n))
然后每次查询,二分答案。检查的时候在对应矩形内求最大值是否大于等于检查值。使用二维RMQ去 O ( 1 ) O(1) O(1)查询,预处理复杂度 O ( n m ∗ l o g ( n m ) ) O(nm*log(nm)) O(nmlog(nm))
总复杂度 O ( n m ∗ l o g ( n m ) + q ∗ l o g ( n ) ) O(nm*log(nm)+q*log(n)) O(nmlog(nm)+qlog(n))

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define fors(i, a, b) for(int i = (a); i < (b); ++i)
using namespace std;
int n, m, Q;
const int maxn = 520;
char s[maxn];
int d[4][maxn][maxn];
int a[maxn][maxn];
bool in(int x, int y){if(x < 1 || x > n || y < 1 || y > m) return false; return true;}
bool block(int x1, int y1, int x2, int y2, int o){
    if(!in(x1, y1) || !in(x2, y2)) return false;
    int sum = (x2-x1+1)*(y2-y1+1);
    return sum == d[o][x2][y2]-d[o][x1-1][y2]-d[o][x2][y1-1]+d[o][x1-1][y1-1];
}
bool check(int x, int y, int r){
    int x1 = x-r+1, y1 = y-r+1, x2, y2;
    if(!block(x1, y1, x, y, 0)) return false;
    y1 += r; y2 = y+r; x2 = x;
    if(!block(x1, y1, x2, y2, 1)) return false;
    x1 += r; x2 += r;
    if(!block(x1, y1, x2, y2, 3)) return false;
    y1 -= r; y2 -= r;
    if(!block(x1, y1, x2, y2, 2)) return false;
    return true;
}
int lg2[maxn];
int dp[9][9][maxn][maxn];
int get_max(int x1, int y1, int x2, int y2){
    int k = lg2[x2-x1+1], l = lg2[y2-y1+1];
    int t1 = max(dp[k][l][x1][y1], dp[k][l][x2-(1<<k)+1][y1]);
    int t2 = max(dp[k][l][x1][y2-(1<<l)+1], dp[k][l][x2-(1<<k)+1][y2-(1<<l)+1]);
    return max(t1, t2);
}
bool check(int x1, int y1, int x2, int y2, int lim){
    if(x1 > x2 || y1 > y2) return false;
    return get_max(x1, y1, x2, y2) >= lim;
}
int main()
{
    lg2[0] = -1;
    fors(i, 1, maxn) lg2[i] = lg2[i>>1]+1;
    cin>>n>>m>>Q;
    fors(i, 1, n+1) {
        scanf("%s", s+1);
        fors(j , 1, m+1)
            if(s[j] == 'G') d[1][i][j] = 1;
            else if(s[j] == 'Y') d[2][i][j] = 1;
            else if(s[j] == 'R') d[0][i][j] = 1;
            else if(s[j] == 'B') d[3][i][j] = 1;
    }
    fors(o, 0, 4)
        fors(i, 1, n+1)
            fors(j, 1, m+1)
                d[o][i][j] += d[o][i][j-1]+d[o][i-1][j]-d[o][i-1][j-1];
    fors(i, 1, n+1) fors(j, 1, m+1){
        int l = 1, r = n;
        while(l <= r){
            if(check(i, j, mid)) a[i][j] = mid, l = mid+1;
            else r = mid-1;
        }
    }
    fors(k, 0, 9)
    fors(l, 0, 9)
    fors(i, 1, n+1)
    fors(j, 1, m+1){
            if(k == 0 && l == 0) {dp[k][l][i][j] = a[i][j]; continue;}
            else if(l == 0) {
                if(i+(1<<(k-1)) <= n)
                    dp[k][l][i][j] = max(dp[k-1][l][i][j], dp[k-1][l][i+(1<<(k-1))][j]);
                else dp[k][l][i][j] = dp[k-1][l][i][j];
            }
            else {
                if(j+(1<<(l-1)) <= m)
                    dp[k][l][i][j] = max(dp[k][l-1][i][j], dp[k][l-1][i][j+(1<<(l-1))]);
                else dp[k][l][i][j] = dp[k][l-1][i][j];
            }
        }
    while(Q--){
        int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int l = 1, r = n;
        int ans = 0;
        while(l <= r){
            if(check(x1+mid-1, y1+mid-1, x2-mid, y2-mid, mid)) ans = mid, l = mid+1;
            else r = mid-1;
        }
        printf("%d\n", 4*ans*ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值