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; }