题解-------[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 ...
随机推荐
- java初学小项目-酒店客房管理系统
最近初次接触JAVA,感觉之前学的C语言很有用,跟着视频做了一个小项目-酒店客房管理系统 /* 酒店客房管理系统 */ import java.util.Scanner;//通过键盘来输入命令需要的引 ...
- 19 01 17 Django 模板 返回一个页面
模板 问题 如何向请求者返回一个漂亮的页面呢? 肯定需要用到html.css,如果想要更炫的效果还要加入js,问题来了,这么一堆字段串全都写到视图中,作为HttpResponse()的参数吗?这样定义 ...
- c语言寒假大作战
一.表格 问题 回答 这个作业属于那个课程 2019级计科一班 这个作业要求在哪里 寒假大作战01 这个作业的目标是 gitee注册.登录.上传文件.克隆仓库与 git基础命令学习与使用 作业正文 作 ...
- 经验分享:Essay写作遇到困难请你这样做
很多留学生在essay写作中可能会遇到很多困难,要么是essay写作内容出现问题,又或者是对于essay写作格式的不了解,导致自己无法顺利完成essay.今天小编就收集了几位留学生的写作经验分享,希望 ...
- 第二章,C语言概述
2.1 简单的C程序示例 #include <stdio.h> #include <stdlib.h> int main(void) { int num; num=; prin ...
- hihocoder:#1082 : 然而沼跃鱼早就看穿了一切(用string)
题目是这样的: 描述 fjxmlhx每天都在被沼跃鱼刷屏,因此他急切的找到了你希望你写一个程序屏蔽所有句子中的沼跃鱼("marshtomp",不区分大小写).为了使句子不缺少成分, ...
- git push 现有代码到一个新的分支
git push origin HEAD:task/xxx-test-local git push的一般形式为 git push <远程主机名> <本地分支名> <远程 ...
- The 2019 China Collegiate Pro gramming Contest Harbin Site (F. Fixing Banners)
F. Fixing Banners time limit per test 1 second memory limit per test 512 megabytes input standard in ...
- SpringMVC:提交参数名与接收参数名问题
1.提交的域名称和处理方法的参数名一致 提交数据 : http://localhost:8080/hello?name=111 处理方法 : @RequestMapping("/hello& ...
- ES7之async/await
async 是 ES7 才有的与异步操作有关的关键字. async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数. async function helloAsync(){ ...