题解-------[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 ...
随机推荐
- DuplicateHandle伪句柄与实句柄的应用二
//扫描进程列表,获得进程名为 ConsoleApplication2.exe的进程句柄B,把当前进程A的伪 //句柄传递给B,在B进程中关闭它 #include "stdafx.h&quo ...
- Vue点击按钮下载对应图片
最近有用到点击某个按钮 自动下载对应图片,可是对于浏览器不同的问题,会有‘个别’浏览器出现不能下载的或者下载的效果不同等的问题, 可以直接用创建canvas方法: 定义图片地址Img: "w ...
- 19 01 15 js 尺寸相关 滚动事件
尺寸相关.滚动事件 1.获取和设置元素的尺寸 width().height() 获取元素width和height innerWidth().innerHeight() 包括padding的width和 ...
- 了解OOM
1)什么是OOM? OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”,来源于java.lang.OutOfMemoryError.看下关于的官方说明: Thrown when ...
- cf1208 D Restore Permutation (二分+树状数组)
题意 让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种) 给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和. 思路 显然,应该倒着来,也就是从p ...
- python3 sort list
1. 对元素指定的某一部分进行排序,关键字排序 s = ['release.10.txt','release.1.txt','release.2.txt','release.14.txt','rele ...
- HashMap源码阅读笔记
HashMap源码阅读笔记 本文在此博客的内容上进行了部分修改,旨在加深笔者对HashMap的理解,暂不讨论红黑树相关逻辑 概述 HashMap作为经常使用到的类,大多时候都是只知道大概原理,比如 ...
- sort()函数使用详解
使用时需要导入头文件<algorithm> #include<algorithm> 语法描述:sort(begin,end,cmp),cmp参数可以没有,如果没有默认非降序排序 ...
- mysql经典查询语句-笔记
笔记来源公开课,谢谢! 1.创建student和score表 CREATE TABLE student ( id INT(10) NOT NULL UNIQUE PRIMARY KEY , name ...
- Win10 MySQL5.7中文乱码问题
https://blog.csdn.net/hh___56789/article/details/87900923 最好把 utf8 都换成utf8mb4 ,以免以后遇到意想不到的错误.utf8有漏洞 ...