【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 1000000009ull
    ull 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;
    }

    代码解释

  • 哈希函数计算:首先计算矩阵的行和列哈希值,使用两个质数作为乘数,分别处理行和列。
  • 枚举中心点:遍历每个可能的中心点,计算不同大小的正方形子矩阵。
  • 对称性检查:对于每个正方形子矩阵,计算其上下和左右翻转后的哈希值,判断是否与原子矩阵的哈希值相等。
  • 结果统计:统计满足条件的正方形子矩阵个数,输出最终结果。
  • 通过这种方法,可以高效地解决问题,避免直接比较子矩阵元素的高时间复杂度,确保在合理时间内完成计算。

    上一篇:【笔记】javafx_TabPane和Tab切换面板组件
    下一篇:【笔记】javafx_Accordion和TitledPane可折叠组件

    发表评论

    最新留言

    关注你微信了!
    [***.104.42.241]2025年04月01日 10时37分23秒