【ZJOI2009】对称的正方形

题面

https://www.luogu.org/problem/P2601

题解

二维哈希(和二维前缀和类似)

右向量:$107$
下向量:$233$

才不会取名叫$wls$和$wym$

upd:突然想到,取$wls$和$wym$也挺好的,因为他们作为两个基向量,被我期待在任何一点永不相交。

(讽刺的是,现实生活中,他们一个在一中,一个在七中,竟然还能谈成。。。)

不想这些无聊的东西了,我还是好好想我女神吧。。。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#define N 1050
#define ri register int
#define uLL unsigned long long
using namespace std;

const uLL p1=107,p2=233;
uLL pp1[N],pp2[N];
int n,m;
int a[N][N];

struct hash{
  uLL sum1[N][N],sum2[N][N],sum3[N][N],sum4[N][N];
  void init() {
    for (ri i=1;i<=n;i++)
      for (ri j=1;j<=m;j++) 
        sum1[i][j]=sum1[i-1][j]*p1+sum1[i][j-1]*p2-sum1[i-1][j-1]*p1*p2+(uLL)a[i][j];
    for (ri i=n;i>=1;i--)
      for (ri j=1;j<=m;j++)
        sum2[i][j]=sum2[i+1][j]*p1+sum2[i][j-1]*p2-sum2[i+1][j-1]*p1*p2+(uLL)a[i][j];
    for (ri i=1;i<=n;i++)
      for (ri j=m;j>=1;j--)
        sum3[i][j]=sum3[i-1][j]*p1+sum3[i][j+1]*p2-sum3[i-1][j+1]*p1*p2+(uLL)a[i][j];
    for (ri i=n;i>=1;i--)
      for (ri j=m;j>=1;j--) 
        sum4[i][j]=sum4[i+1][j]*p1+sum4[i][j+1]*p2-sum4[i+1][j+1]*p1*p2+(uLL)a[i][j];
  }
  
  uLL s1(int a,int b,int x,int y){
    return sum1[x][y]-sum1[a-1][y]*pp1[x-a+1]-sum1[x][b-1]*pp2[y-b+1]+sum1[a-1][b-1]*pp1[x-a+1]*pp2[y-b+1];
  }
  uLL s2(int a,int b,int x,int y){
    return sum2[x][y]-sum2[a+1][y]*pp1[a-x+1]-sum2[x][b-1]*pp2[y-b+1]+sum2[a+1][b-1]*pp1[a-x+1]*pp2[y-b+1];
  }
  uLL s3(int a,int b,int x,int y){
    return sum3[x][y]-sum3[a-1][y]*pp1[x-a+1]-sum3[x][b+1]*pp2[b-y+1]+sum3[a-1][b+1]*pp1[x-a+1]*pp2[b-y+1];
  }
  uLL s4(int a,int b,int x,int y){
    return sum4[x][y]-sum4[a+1][y]*pp1[a-x+1]-sum4[x][b+1]*pp2[b-y+1]+sum4[a+1][b+1]*pp1[a-x+1]*pp2[b-y+1];
  }
  int check1(int x,int y) {
    int lb=1,rb=min(min(x-1,y-1),min(n-x,m-y));
    int ret=0;
    while (lb<=rb) {
      int mid=(lb+rb)/2;
      uLL t1=s1(x-mid,y-mid,x,y);
      uLL t2=s2(x+mid,y-mid,x,y);
      uLL t3=s3(x-mid,y+mid,x,y);
      uLL t4=s4(x+mid,y+mid,x,y);
      if (t1==t2 && t2==t3 && t3==t4) ret=mid,lb=mid+1; else rb=mid-1;
    }
    return ret+1;
  }
  int check2(int x,int y) {
    int lb=1,rb=min(min(x-1,y-1),min(n-1-x,m-1-y));
    int ret=0;
    while (lb<=rb) {
      int mid=(lb+rb)/2;
      uLL t1=s1(x-mid,y-mid,x,y);
      uLL t2=s2(x+1+mid,y-mid,x+1,y);
      uLL t3=s3(x-mid,y+1+mid,x,y+1);
      uLL t4=s4(x+mid+1,y+mid+1,x+1,y+1);
      if (t1==t2 && t2==t3 && t3==t4) ret=mid,lb=mid+1; else rb=mid-1;
    }
    return ret+1;
  }
} H;
int main(){
  pp1[0]=1; pp2[0]=1;
  for (ri i=1;i<N;i++) pp1[i]=pp1[i-1]*p1,pp2[i]=pp2[i-1]*p2;
  scanf("%d %d",&n,&m);
  for (ri i=1;i<=n;i++) 
    for (ri j=1;j<=m;j++) scanf("%d",&a[i][j]);
  H.init();
  int ans=0;
  for (ri i=1;i<=n;i++) 
    for (ri j=1;j<=m;j++) {
      ans+=H.check1(i,j);
      if (a[i][j]==a[i+1][j] && a[i+1][j]==a[i][j+1] && a[i][j+1]==a[i+1][j+1]) ans+=H.check2(i,j);
    }
  cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/shxnb666/p/11279773.html