codeforces 1181C Flag

1181C flag

思维深度还是不够,看了出题人的解答才会了。。。

我们预处理出一个四元组(r,c,color,len)

r,c行号,列号;

len表示宽度为1的从单元格(r,c)向下可以扩展的连续相同颜色的长度;

color表示这一段的颜色。

 

这些信息可以保存在一个二维pair数组中,方便后续使用。

当我们预处理出所有宽度为1的旗帜后便可以以行号为第一层循环,我们将某一块连续区间作为旗帜三要素的中间部分,那么我们只需要判断出其上方的颜色及长度是否满足条件,下方直接连接的部分是否具有与其不同的颜色以及长度是否满足条件,我们便可以知晓宽度为1的满足条件的旗帜的四元组(color1,color2,color3,len),那么如何判断宽度呢,我们只需要判断(r,c+1)是否是一个旗帜,以及他的形状和颜色是否与(r,c)的三部分相同,若是相同则宽度加1;否则宽度置为1,我们从当前列继续向后寻找新的四元组(color1,color2,color3,len),当一行内的内容全部判断完之后,进入下一行去找寻。

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e3+9;

char mapp[maxn][maxn];

pair<char,int> p[maxn][maxn];//预处理宽度为1的每个(r,c)可以向下走的连续相同颜色的长度与颜色;
typedef long long ll;

//预处理宽度为1的旗帜的信息;
void init(int n,int m){

    for(int j=1;j<=m;++j)
        for(int i=1;i<=n;){
            int len=1;
            int r=i,c=j;
            while(i<=n&&mapp[i][j]==mapp[i+1][j]){
                ++i;
                ++len;
            }
            ++i;
            for(int k=r;k<i;++k){
                p[k][c].first=mapp[r][c];
                p[k][c].second=len--;
            }
        }
}

int n,m;

//判断一列中的连续三块是否满足宽度为1的旗帜的条件;
bool shu(int r,int c,int len){
    if(r-len>=1&&r-len<=n&&r+len>=1&&r+len<=n&&p[r-len][c].second>=len&&p[r+len][c].second>=len){
        if(p[r][c].first!=p[r+len][c].first&&p[r][c].first!=p[r-len][c].first) return 1;
        return 0;
    }
    return 0;
}

//判断相邻两列的旗帜是否颜色相同;
bool yanse(int r,int c,int len){
    if(c+1<=m&&p[r][c].first==p[r][c+1].first&&p[r-len][c].first==p[r-len][c+1].first&&p[r+len][c].first==p[r+len][c+1].first) return 1;
    return 0;
}

//判断相邻两列是否可以拼接为旗帜;
bool heng(int r,int c,int len){
    if(c+1<=m&&p[r][c+1].second==len){
        if(shu(r,c+1,len)){
            if(yanse(r,c,len)) return 1;
            return 0;
        }
        return 0;
    }
    return 0;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        scanf("%s",mapp[i]+1);
    memset(p,0,sizeof(p));
    init(n,m);
    if(n<=2){
        printf("0\n");
        return 0;
    }
    ll res=0;
    for(int i=2;i<n;++i){
        int j=1;
        while(j<=m){
            if(p[i][j].second&&shu(i,j,p[i][j].second)){
                int r=i,c=j,len=p[i][j].second;
                int w=1;
                while(j<=m&&heng(i,j,len)){
                    ++j;
                    ++w;
                }
                res+=w*(w+1LL)/2;
            }
            ++j;
        }

    }
    printf("%I64d\n",res);
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值