题解-------[ZJOI2009]对称的正方形
题目大意
找到所有的上下左右都相同的正方形。
思路:二分+二维Hash
这道题我们首先想到不能暴力判断一个正方形是否合法。
然后我们发现当一个正方形合法时,以这个正方形为中心且比它小的正方形也合法。
所以我们可以枚举每个正方形的中心点,二分求出以这个点为中心点的最大合法正方形的边长L,其贡献是 $\frac{L+1}{2}$
我们再回过来讨论如何判断一个正方形是否合法。
如果这个正方形的原来的、上下翻转的和左右翻转的矩阵都一样,那么这个正方形就是合法的。
以这个思路为出发点,我们可以用二维Hash预处理出这个正方形原来的、上下翻转的、左右反转的矩阵,每次判断的时候只要判断这三个矩阵是否相同就可以了。
在枚举中心点的时候要分类讨论奇偶情况,具体见代码。
二维Hash的求法:
先处理行,在处理列,查询和二维前缀和基本相似,但要注意二维Hash的加减有所不同。
部分代码:
void init() {
//一行的哈希值
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] = a[i][j - 1] * B1 + _a[i][j];
//一列的哈希值
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
a[i][j] += a[i - 1][j] * B2;
}
//查询
unsigned long long query(int x, int y, int X, int Y) {
unsigned long long res = a[x][y] - a[X][Y - 1] * pow1[y - Y + 1] - a[X - 1][Y] * pow2[x - X + 1] + a[X - 1][Y - 1] * pow1[y - Y + 1] * pow2[x - X + 1];
return res;
}
代码
#include <cstdio>
#include <iostream> #define RI register int
#define mid (l + r >> 1) using namespace std; template <class T>
inline void read(T &x) {
x = 0; T f = 1; char c = getchar();
while(c > '9' || c < '0') {
if(c == '-')
f = -f;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
x *= f;
} typedef unsigned long long ull;
const int N = 1e3 + 1;
const int B1 = 233;
const int B2 = 332;
int n, m, ans;
ull a[N][N], b[N][N], c[N][N];
ull pow1[N], pow2[N]; inline void Read() {
read(n), read(m);
for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
read(a[i][j]),
b[i][m - j + 1] = a[i][j],//左右翻转
c[n - i + 1][j] = a[i][j];//上下翻转
}
//二维哈希预处理
inline void init() {
for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
a[i][j] += a[i][j - 1] * B1,
b[i][j] += b[i][j - 1] * B1,
c[i][j] += c[i][j - 1] * B1;
for(RI i = 1; i <= n; i++)
for(RI j = 1; j <= m; j++)
a[i][j] += a[i - 1][j] * B2,
b[i][j] += b[i - 1][j] * B2,
c[i][j] += c[i - 1][j] * B2;
pow1[0] = pow2[0] = 1;
for(RI i = 1, tmp = max(n, m); i <= tmp; i++)
pow1[i] = pow1[i - 1] * B1,
pow2[i] = pow2[i - 1] * B2;
}
//判断三个矩阵是否相同
inline bool check(int x, int y, int le) {
//因为会自然溢出的缘故,unsigned 没有小于0的时候 所以不能写x-le<0 (细节
if(x > n || y > m || x < le || y < le)
return false;
ull res1 = a[x][y] - a[x][y - le] * pow1[le] - a[x - le][y] * pow2[le] + a[x - le][y - le] * pow1[le] * pow2[le];
int tmp = y;
y = m - (y - le);//位置要调整(细节
ull res2 = b[x][y] - b[x][y - le] * pow1[le] - b[x - le][y] * pow2[le] + b[x - le][y - le] * pow1[le] * pow2[le];
y = tmp, x = n - (x - le);//位置要调整(细节
ull res3 = c[x][y] - c[x][y - le] * pow1[le] - c[x - le][y] * pow2[le] + c[x - le][y - le] * pow1[le] * pow2[le];
return res1 == res2 && res2 == res3;
}
inline void solve() {
int tmp = min(n, m);
//这里要分两点讨论,边长为偶数的是枚举格点,而边长为奇数的则是枚举格子(细节
for(RI i = 0; i < n; i++)
for(RI j = 0; j < m; j++) {
int l = 1, r = tmp, res = 0;
while(l < r) {
if(check(i + mid, j + mid, mid + mid))
res = mid, l = mid + 1;
else
r = mid;
}
ans += res;
}
for(RI i = 0; i < n; i++)
for(RI j = 0; j < m; j++) {
int l = 1, r = tmp, res = 0;
while(l < r) {
if(check(i + mid, j + mid, mid + mid + 1))
res = mid, l = mid + 1;
else
r = mid;
}
ans += res;
}
ans += n * m; //1格的也算对称正方形,不要漏了(细节
printf("%d\n", ans);
} int main() {
Read();
init();
solve();
return 0;
}
题解-------[ZJOI2009]对称的正方形的更多相关文章
- 【BZOJ1414】[ZJOI2009]对称的正方形(哈希)
[BZOJ1414][ZJOI2009]对称的正方形(哈希) 题面 BZOJ 洛谷 题解 深思熟虑一波,发现一个矩阵如果左右对称的话,那么它每行都是一个回文串,同理,如果上下对称的话,那么每列都是一个 ...
- 【BZOJ1414/3705】[ZJOI2009]对称的正方形 二分+hash
[BZOJ1414/3705][ZJOI2009]对称的正方形 Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们 ...
- bzoj 1414: [ZJOI2009]对称的正方形 manacher算法+單調隊列
1414: [ZJOI2009]对称的正方形 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 331 Solved: 149[Submit][Stat ...
- bzoj 1414: [ZJOI2009]对称的正方形
Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...
- [luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)
传送门 很蒙蔽,不知道怎么搞. 网上看题解有说可以哈希+二分搞,也有的人说用Manacher搞,Manacher是什么鬼?以后再学. 对于这个题,可以从矩阵4个角hash一遍,然后枚举矩阵中的点,再二 ...
- luoguP2601 对称的正方形
题目描述 给出一个数字矩形,求这个矩形中有多少个子正方形满足上下对称.左右对称. 思路 我们可以用3个哈希数组 \(a\ b\ c\) 分别表示矩形从左上往右下看,从左下往右上看,从右上往左下看的样子 ...
- 【bzoj 1414】对称的正方形 单调队列+manacher
Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...
- 题解 P1387 【最大正方形】
传送门 搞不清楚为什么这一题要DP . . . . . . 思路: \(n\le100\),考虑暴力. 要求一大块区间内都是1,考虑前缀和. 在矩阵中求一个符合条件的子矩阵,考虑\(n^3\)的&qu ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
随机推荐
- LeetCode题解分类汇总(包括剑指Offer和程序员面试金典,持续更新)
LeetCode题解汇总(持续更新,并将逐步迁移到本博客列表中) 剑指Offer 数据结构 链表 序号 题目 难度 06 从尾到头打印链表 简单 18 删除链表的节点 简单 22 链表中倒数第k个节点 ...
- filter滤镜兼容ie的rgba属性
要在一个页面中设置一个半透明的白色div.这个貌似不是难题,只需要给这个div设置如下的属性即可: background: rgba(255,255,255,0.1); 但是要兼容到ie8.这个就有点 ...
- 67.ORM查询条件:range的使用,使用make_aware将navie time 转换为aware time
模型的定义,models.py文件中示例代码如下: from django.db import models # 在定义模型的类时,一定要继承models.Model class Category(m ...
- JVM探秘:jinfo查看JVM运行时参数
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. 如何查看JVM运行时参数,对于线上JVM调优是很关键的,因为只有知道了当前使用的JVM ...
- 服务器上安装解决ole错误
服务器上安装此插件 提取码:9kiw
- centos7 lvm合并分区脚本初探-linux性能测试 -centos7修改网卡名字-jdk环境安装脚本-关键字查询文件-批量添加用户
1.#!/bin/bash lvmdiskscan | grep centos > /root/a.txt a=`sed -n '1p' /root/a.txt` b=`sed -n '2p' ...
- 把a表格的内容读取出来,然后写到b表格
把a表格的内容读取出来,然后写到b表格 #!/usr/bin/env python3 import sys #控制台要输入的两个参数格式为:python script_name.py 参数1 参数2 ...
- ArchLinux安装Gnome桌面
给Arch安装Gnome桌面美化及常用软件配置 一.创建普通用户 1.安装zsh 个人比较喜欢的一个shell,你们可以和我不同 # pacman -S zsh 2.创建用户 kain是我创建用户的名 ...
- IDEA--安装
1:下载IDEA 官网:http://www.jetbrains.com/idea/download/#section=windows(选择下载.zip) 2:解压 3:破解: 1)在C:\Windo ...
- sort()函数使用详解
使用时需要导入头文件<algorithm> #include<algorithm> 语法描述:sort(begin,end,cmp),cmp参数可以没有,如果没有默认非降序排序 ...