题目描述

给出一个数字矩形,求这个矩形中有多少个子正方形满足上下对称、左右对称。

思路

我们可以用3个哈希数组 \(a\ b\ c\) 分别表示矩形从左上往右下看,从左下往右上看,从右上往左下看的样子,那么我们可以得到:

  1. 如果正方形 \((x,y,u,v)\)(即以 \((x,y)\) 这一格为左上角,\((u,v)\) 为右下角的正方形)左右对称,那么它从左上往右下看和从右上往左下看是一样的,即 \(a\) 哈希数组和 \(c\) 哈希数组相等。
  2. 如果正方形 \((x,y,u,v)\) 上下对称,那么它从左上往右下看和从左下往右上看是一样的,即 \(a\) 哈希数组和 \(b\) 哈希数组相等。

如果两条条件都满足,那么这个正方形就是对称的正方形。

我们可以分边有奇数个节点和边有偶数个节点的正方形枚举它的中心点,显然,答案是具有单调性的,于是我们就可以进行二分答案求值。

实现

我们通过处理出 \((1,1,i,j)\) 矩形的哈希值,那么就可以通过类似前缀和的方式来分别得到正方形 \((x,y,u,v)\) 的 \(a\ b\ c\) 三个值。柿子如下:

q.a=a[u][v]-a[u][y-1]*p1[v-y+1]-a[x-1][v]*p2[u-x+1]+a[x-1][y-1]*p1[v-y+1]*p2[u-x+1];
q.b=b[x][v]-b[x][y-1]*p1[v-y+1]-b[u+1][v]*p2[u-x+1]+b[u+1][y-1]*p1[v-y+1]*p2[u-x+1];
q.c=c[u][y]-c[u][v+1]*p1[v-y+1]-c[x-1][y]*p2[u-x+1]+c[x-1][v+1]*p1[v-y+1]*p2[u-x+1];

然后进行判断即可。

Code

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
typedef unsigned long long ull;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
inline int min(int a,int b){return a<b?a:b;}inline int max(int a,int b){return a>b?a:b;}
inline void pi(int x){pf("%d ",x);}inline void pn(){pf("\n");}
inline void file(){freopen("in.in","r",stdin);freopen("my.out","w",stdout);}
const int N=1e3+10;
int n,m,num[N][N],tot;ull a[N][N],b[N][N],c[N][N],p1[N],p2[N];
struct node{ull a,b,c;}q;
inline void get(int x,int y,int u,int v){
q.a=a[u][v]-a[u][y-1]*p1[v-y+1]-a[x-1][v]*p2[u-x+1]+a[x-1][y-1]*p1[v-y+1]*p2[u-x+1];
q.b=b[x][v]-b[x][y-1]*p1[v-y+1]-b[u+1][v]*p2[u-x+1]+b[u+1][y-1]*p1[v-y+1]*p2[u-x+1];
q.c=c[u][y]-c[u][v+1]*p1[v-y+1]-c[x-1][y]*p2[u-x+1]+c[x-1][v+1]*p1[v-y+1]*p2[u-x+1];
}
inline short main(){
p1[0]=p2[0]=1;
n=read(),m=read();
F(i,1,N-10)p1[i]=p1[i-1]*131,p2[i]=p2[i-1]*13331;
F(i,1,n)F(j,1,m)num[i][j]=read();
//求哈希值
F(i,1,n)F(j,1,m)a[i][j]=a[i][j-1]*131+a[i-1][j]*13331-a[i-1][j-1]*131*13331+num[i][j];
D(i,n,1)F(j,1,m)b[i][j]=b[i][j-1]*131+b[i+1][j]*13331-b[i+1][j-1]*131*13331+num[i][j];
F(i,1,n)D(j,m,1)c[i][j]=c[i][j+1]*131+c[i-1][j]*13331-c[i-1][j+1]*131*13331+num[i][j];
//偶数边长
F(i,1,n-1){
F(j,1,m-1){
int l=1,r=min(min(n-i,i),min(j,m-j)),ans=0;
while(l<=r){
int mid=(l+r)>>1;
get(i-mid+1,j-mid+1,i+mid,j+mid);
if(q.a==q.b&&q.a==q.c)l=mid+1,ans=mid;
else r=mid-1;
}tot+=ans;
}
}
//奇数边长
F(i,1,n){
F(j,1,m){
int l=1,r=min(min(n-i+1,i),min(m-j+1,j)),ans=0;
while(l<=r){
int mid=(l+r)>>1;
get(i-mid+1,j-mid+1,i+mid-1,j+mid-1);
if(q.a==q.b&&q.a==q.c)l=mid+1,ans=mid;
else r=mid-1;
}tot+=ans;
}
}
pi(tot);
return 0;
}
}
signed main(){return EMT::main();}

luoguP2601 对称的正方形的更多相关文章

  1. bzoj 1414: [ZJOI2009]对称的正方形 manacher算法+單調隊列

    1414: [ZJOI2009]对称的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 331  Solved: 149[Submit][Stat ...

  2. 【BZOJ1414】[ZJOI2009]对称的正方形(哈希)

    [BZOJ1414][ZJOI2009]对称的正方形(哈希) 题面 BZOJ 洛谷 题解 深思熟虑一波,发现一个矩阵如果左右对称的话,那么它每行都是一个回文串,同理,如果上下对称的话,那么每列都是一个 ...

  3. 【BZOJ1414/3705】[ZJOI2009]对称的正方形 二分+hash

    [BZOJ1414/3705][ZJOI2009]对称的正方形 Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们 ...

  4. [luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

    传送门 很蒙蔽,不知道怎么搞. 网上看题解有说可以哈希+二分搞,也有的人说用Manacher搞,Manacher是什么鬼?以后再学. 对于这个题,可以从矩阵4个角hash一遍,然后枚举矩阵中的点,再二 ...

  5. 【bzoj 1414】对称的正方形 单调队列+manacher

    Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...

  6. bzoj 1414: [ZJOI2009]对称的正方形

    Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...

  7. 题解-------[ZJOI2009]对称的正方形

    传送门 题目大意 找到所有的上下左右都相同的正方形. 思路:二分+二维Hash 这道题我们首先想到不能暴力判断一个正方形是否合法. 然后我们发现当一个正方形合法时,以这个正方形为中心且比它小的正方形也 ...

  8. hdu4618 Palindrome Sub-Array dp+记忆化搜索 或者直接暴力

    题意就是找一个 左右上下对称的正方形矩阵. 连接:http://acm.hdu.edu.cn/showproblem.php?pid=4618 没想到记忆+dp和暴力就能水过... //记忆话搜索+d ...

  9. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. Windows环境mysql自动备份

    1.编写bat文件备份mysql 1 rem ******MySQL backup start****** 2 @echo off 3 4 ::删除一周前的备份数据 5 forfiles /p &qu ...

  2. JS高阶函数的使用

    1.何为高阶函数呢? JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数.简单来说,就是对其他 ...

  3. 北京大公司:你是熟悉Map集合吗?

    <对线面试官>系列目前已经连载30篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...

  4. 团队开发day02

    进行android的UI界面设计,设计圆角输入框和圆形按钮, 以及点击的水滴效果 遇到问题,新建的drawable布局没有达到预期的效果,圆形按钮的 背景想设置为图片,但是发现会遮盖住水滴效果,改用新 ...

  5. 论文阅读:LIC-Fusion: LiDAR-Inertial-Camera Odometry

    本文提出了一种紧耦合的多传感器(雷达-惯导-相机)融合算法,将IMU测量.稀疏视觉特征.提取的激光点融合.提出的算法在时间和空间上对三个异步传感器进行在线校准,补偿校准发生的变化.贡献在于将检测和追踪 ...

  6. poj 折半搜索

    poj2549 Sumsets 题目链接: http://poj.org/problem?id=2549 题意:给你一个含有n(n<=1000)个数的数列,问这个数列中是否存在四个不同的数a,b ...

  7. Ubuntu 18.04 开启 root 账号并允许远程连接

    转载:https://blog.csdn.net/u010766726/article/details/105376461 以普通用户登录系统 通过 "终端" 操作 普通用户 – ...

  8. Springboot+Mybatis+小程序

    思维导图: 项目效果图 一览界面: 新增界面:

  9. 【Java基础上】一、简述Java

    一.简述Java ​ Java是一种高级的面向对象的程序语言,在此处,不需要了解什么叫做面向对象,因为后面的文章中自然会谈到这方面的论述.那么,Java就是一个计算机的编程语言. 1.1 Java的历 ...

  10. python---replace函数

    描述 Python replace() 方法把字符串中的 old(旧字符串) 替换成 new(新字符串),如果指定第三个参数max,则替换不超过 max 次. 语法 replace()方法语法: st ...