生日礼物(题解)

题目描述


  10月11日是MM的生日,Matrix67打算自己DIY一些抱枕送给MM。Matrix67手中有一块矩形花布,花布分成了M x N个小格子,有些格子的花色相同,有些格子的花色不同。为了使最终成品更美观,Matrix67希望用于DIY的布匹都是正方形的,并且满足布匹花色上下对称且左右对称。为此,他希望能计算出这块花布里一共包含有多少个上下对称且左右对称的小正方形。

  举例来说,Matrix67手中的花布大小为6 x 4,上面共有5种花色:

ABACDA

DCDEAA

ABABAA

DDCBBA

  则这块布里一共有26个上下对称且左右对称的正方形,其中包括最左上角的3x3正方形、右边4个A组成的2x2正方形,当然还有24个1x1的小正方形。

输入格式


第一行输入两个用空格隔开的正整数M,N,表示Matrix67手中的格子布分为M行N列。

  以下M行每行N个字符,描述布匹的花色。我们用26个大写字母来区别不同的花色,相同的字母代表相同的花色,不同的字母代表不同的花色。

输出格式


输出在Matrix67的格子布中切出一块花色左右对称且上下对称的正方形共有多少种方案。

样例输入


4 6
ABACDA
DCDEAA
ABABAA
DDCBBA

样例输出


26

Solution


首先对于一条边来说,它的长度分偶数与奇数的情况,对于偶数来说,他是没有对称中心的,所以要分情况讨论。

首先我们先预处理出每一个格子对于横向和纵向所能拓展的最长长度。时间复杂度是 O n

然后枚举每一个格子 判断情况是否存在

代码:

 //By Bibi
///                 .-~~~~~~~~~-._       _.-~~~~~~~~~-.
///             __.'              ~.   .~              `.__
///           .'//                  \./                  \\`.
///        .'//                     |                     \\`.
///       .'// .-~"""""""~~~~-._     |     _,-~~~~"""""""~-. \\`.
///     .'//.-"                 `-.  |  .-'                 "-.\\`.
///   .'//______.============-..   \ | /   ..-============.______\\`.
/// .'______________________________\|/______________________________`.
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN=210;
int read(){
    int sum=0,flag=1;
    char c;
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=-1;
    for(;c>='0'&&c<='9';c=getchar())sum=(sum<<1)+(sum<<3)+c-'0';
    return sum*flag;
}
int n,m;
char c[MAXN][MAXN],s;
int x[MAXN][MAXN],y[MAXN][MAXN];
int ans;
void init(){
    n=read();m=read();
    rep(i,1,n){
        rep(j,1,m) c[i][j]=getchar();
        s=getchar();
    }
}
void DP(){

    //奇数情况 
    memset(x,0,sizeof x);
    memset(y,0,sizeof y);
    rep(i,1,n)
    rep(j,1,m){
        int k=1;
        while(i-k>=1&&i+k<=n)
            if(c[i-k][j]==c[i+k][j]) ++k;
            else break;
        y[i][j]=k-1;
        k=1;
        while(j-k>=1&&j+k<=m)
            if(c[i][j-k]==c[i][j+k]) ++k;
            else break;
        x[i][j]=k-1;
    }
    rep(i,1,n)
    rep(j,1,m){
        int k=0;
        int temp=min(x[i][j],y[i][j]);
        while(i-k>=1&&i+k<=n&&j-k>=1&&j+k<=m){
            ++ans;
            ++k;
            temp=min(temp,x[i-k][j]);
            temp=min(temp,x[i+k][j]);
            temp=min(temp,y[i][j+k]);
            temp=min(temp,y[i][j-k]);
            if(temp<k) break;
        }
    }

    //偶数情况 

    memset(x,0,sizeof x);
    memset(y,0,sizeof y);
    rep(i,1,n)
    rep(j,1,m){
        int k=1;
        while(i-k+1>=1&&i+k<=n)
            if(c[i-k+1][j]==c[i+k][j]) ++k;
            else break;
        y[i][j]=k-1;
        k=1;
        while(j-k+1>=1&&j+k<=m)
            if(c[i][j-k+1]==c[i][j+k]) ++k;
            else break;
        x[i][j]=k-1;
    }
    rep(i,1,n)
    rep(j,1,m){
        int k=0;
        int temp=min(x[i][j],y[i][j]);
        while(i-k+1>=1&&i+k<=n&&j-k+1>=1&&j+k<=m){
            ++k;
            temp=min(temp,x[i-k+1][j]);
            temp=min(temp,x[i+k][j]);
            temp=min(temp,y[i][j+k]);
            temp=min(temp,y[i][j-k+1]);
            if(temp<k) break;
            ++ans;
        }
    }
}
int main(){
    init();
    DP();
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bbbblzy/article/details/80314711