Codeforces Round #619 (Div. 2) E. Nanosoft 前缀和

E. Nanosoft

Question:
定义一个logo 形状颜色如下类推 ,现在有一个关于logo的颜色矩阵在这里插入图片描述
长n宽m 并有q次询问:r1,c1 r2,c2 直接最大的logo有多大
n,m<=500 q<=1000;
Solution:
记录每种颜色数量的二维前缀和 ,那么对于一个区域 是否为logo只需分别判断其中颜色数量即可,并且以某个点为起点的logo最多只有一个 ,所以我们可以暴力直接枚举答案长度 和起点一直更新答案即可 时间复杂度为O(min(n,m)/2nm)此题是可以解决的
但当n,m<1000时我们怎么解决呢?
通过观察发现每一个大的logo都包含比他小的logo,满足单调性,考虑二分。
可以预处理出每个点的答案(假设i,j为红色右下角,向四周判断周围的颜色数量复杂度O(nm))后建立一个 二维ST表(O(nmlg(nm)) 查询即可

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define warn printf("!!!***!\n")
#define all(x) (x).begin(),(x).end()
#define SZ(x)  ((int)(x).size());
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
typedef vector<int> VI;
typedef vector<LL> VL;
const int maxn=2e6+6;
const int oo=0x3fffffff;
const int mod=1e9+7;
int n,m,qq,cnt[5][555][555],r1[maxn],c1[maxn],r2[maxn],c2[maxn],ans[maxn];
char s[555][555];
int ask(int k,int r1,int c1,int r2,int c2)
{
    return cnt[k][r2][c2]-cnt[k][r2][c1-1]-cnt[k][r1-1][c2]+cnt[k][r1-1][c1-1];
}
int main()
{
    scanf("%d%d%d",&n,&m,&qq);
    rep(i,1,n){
        scanf("%s",s[i]+1);
        rep(j,1,m){
             if(s[i][j]=='R') cnt[0][i][j]=1;
             if(s[i][j]=='G') cnt[1][i][j]=1;
             if(s[i][j]=='Y') cnt[2][i][j]=1;
             if(s[i][j]=='B') cnt[3][i][j]=1;
        }
    }
    rep(k,0,3){
        rep(i,1,n) rep(j,1,m) cnt[k][i][j]+=cnt[k][i-1][j];
        rep(i,1,n) rep(j,1,m) cnt[k][i][j]+=cnt[k][i][j-1];
    }

    rep(i,1,qq) scanf("%d%d%d%d",&r1[i],&c1[i],&r2[i],&c2[i]);

    rep(l,1,250) {
        if(2*l>n||2*l>m) break;

        rep(i,1,n) rep(j,1,m) cnt[4][i][j]=0;

        for(int i=1;i<=n-2*l+1;i++) for(int j=1;j<=m-2*l+1;j++){
            if(ask(0,i,j,i+l-1,j+l-1)==l*l&&ask(1,i,j+l,i+l-1,j+2*l-1)==l*l
               &&ask(2,i+l,j,i+2*l-1,j+l-1)==l*l&&ask(3,i+l,j+l,i+2*l-1,j+2*l-1)==l*l)
                cnt[4][i][j]=1;
                //cout<<i<<','<<j<<endl;
        }

        for(int i=1;i<=n-2*l+1;i++) for(int j=1;j<=m-2*l+1;j++) cnt[4][i][j]+=cnt[4][i-1][j];

        for(int i=1;i<=n-2*l+1;i++) for(int j=1;j<=m-2*l+1;j++) cnt[4][i][j]+=cnt[4][i][j-1];


        rep(i,1,qq) {
            if(r2[i]-r1[i]+1>=2*l&&c2[i]-c1[i]+1>=2*l&&ask(4,r1[i],c1[i],r2[i]-l*2+1,c2[i]-l*2+1)){
                ans[i]=l;
            }
        }
    }
    rep(i,1,qq) printf("%d\n",4*ans[i]*ans[i]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值