Codeforces Round #619 (Div. 2) E. Nanosoft(二維前綴和+二分+二維ST表)

題目鏈接:https://codeforces.com/contest/1301/problem/E

 

題目大意:

  左上角紅,右上角綠,左下角黃,右下角藍的正方形被算作合格的logo,給一張圖和一個範圍,問範圍內最大的合格logo有多大

 

題目思路:

  三步走,第一步,求各種顏色數量的二維前綴和。
  第二步,假設每一個點作爲紅色的右下角,能形成多大的logo,通過二分實現,check的條件就是左上右上左下右下都是指定的顏色, 就是規定範圍內的顏色數量正好是規定範圍大小。
  第三步,對第二步得到的大小進行ST表預處理,然後二分每種顏色的邊長,由於之前處理的是針對紅色的,所以這裏也是。爲了防止這傢伙越過三八線,所以這裏有個很巧妙地操作,就是一定要在合法區域內選擇紅色區域的右下角,他必須距離左邊和上邊mid-1,但是距離右邊和底邊是mid,因爲那塊區域是別的顏色負責的,要是這個範圍內能找到值大於等於mid的,那都是沒毛病的,都可以在選定範圍內出現。

 

以下是代碼:

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int MAXN = 505+5;
const int MOD = 1e9+7;
char s[MAXN][MAXN];
int n,m,q,sum[MAXN][MAXN][4],a[MAXN][MAXN];
int f[10][10][MAXN][MAXN],lg[MAXN];
void Build_2D_Sparse_Table(int n, int m){
    int i, j, k1, k2;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            f[0][0][i][j]=a[i][j];
        }
    }

    for(i = 2; i < MAXN ; i++)
        lg[i] = 1 + lg[i/2];

    for(i = 1; i <= n; i++)
        for(k2 = 1; (1 << k2) <= m; k2++)
            for(j = 1; j <= m - (1 << k2) + 1; j++)
                f[0][k2][i][j] = max(f[0][k2 - 1][i][j], f[0][k2 - 1][i][j + (1 << (k2 - 1))]);

    for(k1 = 1; (1 << k1) <= n; k1++)
        for(i = 1; i <= n - (1 << k1) + 1; i++)
            for(k2 = 0; (1 << k2) <= m; k2++)
                for(j = 1; j <= m - (1 << k2) + 1; j++)
                    f[k1][k2][i][j] = max(f[k1 - 1][k2][i][j], f[k1 - 1][k2][i + (1 << (k1 - 1))][j]);
}

int Query(int x1, int y1, int x2, int y2){
    int k1 = lg[x2 - x1 + 1], k2 = lg[y2 - y1 + 1];
    x2 = x2 - (1 << k1) + 1;
    y2 = y2 - (1 << k2) + 1;
    return max(max(f[k1][k2][x1][y1],f[k1][k2][x1][y2]),max(f[k1][k2][x2][y1],f[k1][k2][x2][y2]));
}
int getsum(int x1,int y1,int x2,int y2,int c){
    if(x1<1||x1>n)return 0;
    if(x2<1||x2>n)return 0;
    if(y1<1||y1>m)return 0;
    if(y2<1||y2>m)return 0;
    return sum[x2][y2][c]-sum[x1-1][y2][c]-sum[x2][y1-1][c]+sum[x1-1][y1-1][c];
}
bool check(int x,int y,int val){
    if(getsum(x-val+1,y-val+1,x,y,0)<val*val)return false;
    if(getsum(x-val+1,y+1,x,y+val,1)<val*val)return false;
    if(getsum(x+1,y-val+1,x+val,y,2)<val*val)return false;
    if(getsum(x+1,y+1,x+val,y+val,3)<val*val)return false;

    return true;
}
int check2(int r1,int c1,int r2,int c2,int mid){
    if(r1>r2||c1>c2)return false;
    return Query(r1,c1,r2,c2)>=mid;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&q)){
        rep(i,1,n){
            scanf("%s",s[i]+1);
        }
        memset(sum,0,sizeof(sum));
        rep(i,1,n){
            rep(j,1,m){
                rep(k,0,3){
                    sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
                }
                if(s[i][j]=='R')sum[i][j][0]++;
                if(s[i][j]=='G')sum[i][j][1]++;
                if(s[i][j]=='Y')sum[i][j][2]++;
                if(s[i][j]=='B')sum[i][j][3]++;
            }
        }
        rep(i,1,n){
            rep(j,1,m){
                int l=0,r=min(n,m),ans=0;
                while(l<=r){
                    int mid=(l+r)>>1;
                    if(check(i,j,mid)){
                        ans=mid;
                        l=mid+1;
                    }
                    else r=mid-1;
                }
                a[i][j]=ans;
            }
        }
        Build_2D_Sparse_Table(n,m);
        while(q--){
            int r1,c1,r2,c2;
            scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
            int l=0,r=min(n,m),ans=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(check2(r1+mid-1,c1+mid-1,r2-mid,c2-mid,mid)){
                    l=mid+1;
                    ans=4*mid*mid;
                }
                else r=mid-1;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
發佈了281 篇原創文章 · 獲贊 29 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章