
【ybt高效进阶2-2-3】【luogu P2601】对称正方形
哈希技术:使用两个不同的质数作为乘数,分别计算行和列的哈希值。这样可以快速判断子矩阵的对称性。 枚举中心点:遍历矩阵中的每一个可能的中心点,计算不同大小的正方形子矩阵。 对称性检查:对于每个正方形子矩阵,计算其上下和左右翻转后的哈希值,检查是否与原子矩阵的哈希值相等。 统计结果:统计满足条件的正方形子矩阵的个数。 哈希函数计算:首先计算矩阵的行和列哈希值,使用两个质数作为乘数,分别处理行和列。 枚举中心点:遍历每个可能的中心点,计算不同大小的正方形子矩阵。 对称性检查:对于每个正方形子矩阵,计算其上下和左右翻转后的哈希值,判断是否与原子矩阵的哈希值相等。 结果统计:统计满足条件的正方形子矩阵个数,输出最终结果。
发布日期:2021-05-07 06:59:29
浏览次数:18
分类:精选文章
本文共 4876 字,大约阅读时间需要 16 分钟。
要解决上下对称且左右对称的正方形子矩阵个数的问题,可以使用哈希技术来高效地快速判断子矩阵的对称性。以下是详细的解决方案:
思路概述
详细步骤
矩阵处理:
- 将原矩阵转换为两种翻转后的矩阵:一种是上下翻转,另一种是左右翻转。
- 为了计算哈希值,选择两个不同的质数作为乘数,分别用于行和列的哈希计算。
哈希值计算:
- 从左到右计算行的哈希值,每次乘以质数z1,再加上当前元素的值。
- 从上到下计算列的哈希值,每次乘以质数z2,再加上当前元素的值。
枚举子矩阵:
- 对于每一个可能的中心点,计算以该中心点为中心的不同大小的正方形子矩阵。
- 对于奇数大小的正方形,中心点确定;对于偶数大小的正方形,中心点在两个点之间。
对称性检查:
- 检查上下对称性:计算子矩阵的上下翻转哈希值,与原子矩阵的哈希值比较。
- 检查左右对称性:计算子矩阵的左右翻转哈希值,与原子矩阵的哈希值比较。
- 如果两个哈希值都相等,则说明该子矩阵满足上下和左右对称性。
结果统计:
- 统计所有满足条件的正方形子矩阵的个数,即为最终答案。
代码实现
#include#include using namespace std;#define di1 1000000007ull#define di2 1000000009ullull times1[1001], times2[1001];ull hash[1001][1001], hash_up[1001][1001], hash_left[1001][1001];int n, m, a[1001][1001], ans, tot;void computeHash() { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { hash[i][j] = (hash[i][j-1] * di1 + a[i][j]) % di1; hash_up[i][j] = (hash_up[i][j-1] * di1 + a[n - i + 1][j]) % di1; hash_left[i][j] = (hash_left[i][j-1] * di1 + a[i][m - j + 1]) % di1; } times1[i] = (times1[i-1] * di1) % di1; } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { hash[i][j] = (hash[i][j] + hash[i-1][j] * di2) % di1; hash_up[i][j] = (hash_up[i][j] + hash_up[i-1][j] * di2) % di1; hash_left[i][j] = (hash_left[i][j] + hash_left[i-1][j] * di2) % di1; } }}void ch(int rx, int ry, int dis, int is_up) { int lx = rx - dis + 1; int ly = ry - dis + 1; if (is_up) { lx = n - (rx - dis); ly = ry - dis + 1; } else { lx = rx - dis + 1; ly = m - (ry - dis); } if (lx < 1 || lx > n || ly < 1 || ly > m) return 0; int hash_val = 0; if (is_up) { hash_val = hash_up[rx][ry] - hash_up[rx][ly - 1] * times1[dis] - hash_up[lx - 1][ry] * times2[dis] + hash_up[lx - 1][ly - 1] * times1[dis] * times2[dis]; } else { hash_val = hash[rx][ry] - hash[rx][ly - 1] * times1[dis] - hash[lx - 1][ry] * times2[dis] + hash[lx - 1][ly - 1] * times1[dis] * times2[dis]; } hash_val %= di1; return hash_val;}int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { a[i][j] = (a[i][j] + a[i][j-1]) % di1; int up_row = n - i + 1; a[up_row][j] = (a[up_row][j] + a[up_row][j-1]) % di1; int left_col = m - j + 1; a[i][left_col] = (a[i][left_col] + a[i][left_col-1]) % di1; } } times1[0] = 1; times2[0] = 1; for (int i = 1; i <= n; ++i) { times1[i] = (times1[i-1] * di1) % di1; } for (int i = 1; i <= m; ++i) { times2[i] = (times2[i-1] * di2) % di2; } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { a[i][j] = (a[i][j] + a[i-1][j] * di2) % di1; int up_row = n - i + 1; a[up_row][j] = (a[up_row][j] + a[up_row-1][j] * di2) % di1; int left_col = m - j + 1; a[i][left_col] = (a[i][left_col] + a[i][left_col-1] * di2) % di1; } } tot = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { int max_len = min(i, n - i + 1); max_len = min(max_len, j); max_len = min(max_len, m - j + 1); int odd = 1; int l = 1, r = 0; while (l <= r) { mid = (l + r) >> 1; if (i - mid + 1 < 1 || i + mid - 1 > n || j - mid + 1 < 1 || j + mid - 1 > m) { r = mid - 1; continue; } int x = i + mid - 1; int y = j + mid - 1; if (ch(x, y, mid, 0)) { tot += mid; l = mid + 1; } else { r = mid - 1; } } l = 1, r = min(i, n - i); r = min(r, j); r = min(r, m - j); while (l <= r) { mid = (l + r) >> 1; if (i - mid + 1 < 1 || i + mid > n || j - mid + 1 < 1 || j + mid > m) { r = mid - 1; continue; } int x = i + mid; int y = j + mid; if (ch(x, y, mid, 1)) { tot += mid; l = mid + 1; } else { r = mid - 1; } } } } printf("%d", tot); return 0;}
代码解释
通过这种方法,可以高效地解决问题,避免直接比较子矩阵元素的高时间复杂度,确保在合理时间内完成计算。
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年04月01日 10时37分23秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
面试问道nginx优化怎么做的
2019-03-05
自学linux毕业shell面试题
2019-03-05
4 Java 访问控制符号的范围
2019-03-05
第9章 - 有没有替代原因(检验证据)
2019-03-05
VUE3(八)setup与ref函数
2019-03-05
Vue之Element标签页保留用户操作缓存。
2019-03-05
智能合约开发实践(1)
2019-03-05
2. Spring Boot学习——Yaml等配置文件教程
2019-03-05
MATLAB——操作矩阵的常用函数
2019-03-05
CMake自学记录,看完保证你知道CMake怎么玩!!!
2019-03-05
Eigen库中vector.transpose()函数什么意思
2019-03-05
ORB-SLAM2:LocalMapping线程学习随笔【李哈哈:看看总有收获篇】
2019-03-05
ORB-SLAM2:LoopClosing线程学习随笔【李哈哈:看看总有收获篇】
2019-03-05
牛客练习赛56 D 小翔和泰拉瑞亚(线段树)
2019-03-05
hdu6434 Problem I. Count(数论)(好题)
2019-03-05
NC15553 数学考试(线性DP)
2019-03-05