ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究。最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵。通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数。 Orez自然很想知道这个数是多少,可是矩阵太大,无法去数。只能请你编个程序来计算出这个数。

Input

文件的第一行为两个整数n和m。接下来n行每行包含m个正整数,表示Orez得到的矩阵。

Output

文件中仅包含一个整数answer,表示矩阵中有answer个上下左右对称的正方形子矩阵。
 
hash+二分确定每个中心的最大对称正方形
#include<cstdio>
char buf[12000007],*ptr=buf;
int _(){
    int x=0;
    while(*ptr<48)++ptr;
    while(*ptr>47)x=x*10+*ptr++-48;
    return x;
}
typedef unsigned int u32;
int n,m;
int a[1007][1007];
u32 f[3][1007][1007],pp1[1007],pp2[1007];
long long ans=0;
const u32 p1=1015415441,p2=1115415451;
#define F(i,n) for(int i=1;i<=n;++i)
#define Fd(i,n) for(int i=n;i>=1;--i)
int min(int a,int b){return a<b?a:b;}
bool chk(int l1,int r1,int l2,int r2){
    u32 v1=pp1[r1-l1+1];
    u32 v2=pp2[r1-l1+1];
    u32 h0=f[0][r1][r2]-f[0][r1][l2-1]*v2-(f[0][l1-1][r2]-f[0][l1-1][l2-1]*v2)*v1;
    u32 h1=f[1][r1][l2]-f[1][r1][r2+1]*v2-(f[1][l1-1][l2]-f[1][l1-1][r2+1]*v2)*v1;
    if(h0!=h1)return 0;
    u32 h2=f[2][l1][r2]-f[2][l1][l2-1]*v2-(f[2][r1+1][r2]-f[2][r1+1][l2-1]*v2)*v1;
    return h0==h2;
}
int main(){
    fread(buf,1,sizeof(buf),stdin);
    n=_(),m=_();
    F(i,n)F(j,m)f[0][i][j]=f[1][i][j]=f[2][i][j]=a[i][j]=_();
    F(i,n){
        F(j,m)f[0][i][j]+=f[0][i][j-1]*p2;
        F(j,m)f[0][i][j]+=f[0][i-1][j]*p1;
    }
    F(i,n){
        Fd(j,m)f[1][i][j]+=f[1][i][j+1]*p2;
        Fd(j,m)f[1][i][j]+=f[1][i-1][j]*p1;
    }
    Fd(i,n){
        F(j,m)f[2][i][j]+=f[2][i][j-1]*p2;
        F(j,m)f[2][i][j]+=f[2][i+1][j]*p1;
    }
    pp1[0]=pp2[0]=1;
    F(i,n)pp1[i]=pp1[i-1]*p1;
    F(i,m)pp2[i]=pp2[i-1]*p2;
    
    F(i,n)F(j,m){
        int L=0,R=min(min(i-1,n-i),min(j-1,m-j)),M=1;
        while(L<R){
            if(chk(i-M,i+M,j-M,j+M))L=M;
            else R=M-1;
            M=L+R+1>>1;
        }
        ans+=L+1;
    }
    F(i,n-1)F(j,m-1)if(a[i][j]==a[i][j+1]&&a[i][j]==a[i+1][j]&&a[i][j]==a[i+1][j+1]){
        int L=0,R=min(min(i-1,n-1-i),min(j-1,m-1-j)),M=1;
        while(L<R){
            if(chk(i-M,i+M+1,j-M,j+M+1))L=M;
            else R=M-1;
            M=L+R+1>>1;
        }
        ans+=L+1;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted on 2017-08-01 10:59  nul  阅读(677)  评论(0编辑  收藏  举报