题解 P4398 [JSOI2008]Blue Mary的战役地图

Posted chz-hc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P4398 [JSOI2008]Blue Mary的战役地图相关的知识,希望对你有一定的参考价值。

题目链接:LuoguP4398

二维哈希 (+) 哈希表

[Large exttt{description}]

给出一个(n),再给出(2)(n * n)的矩阵

求最大的(k)满足(2)个矩阵中都有(k * k)的矩阵相同

数据范围 (n leq 50)

[Large exttt{Solution}]

(ullet) 做法(1:)

我们枚举一个边长(k), 枚举第一个矩阵的一个坐标((x, y)),再枚举第二个矩阵的一个坐标((x_1, y_1))然后(O(n ^ 2))判断两个矩阵是否相同

时间复杂度:(O(n ^ 7))

也可以二分(k)

时间复杂度(O(log~n* n ^ 6))没啥用

吸氧即可过

(ullet) 做法(2:)

我们可以用二维哈希来优化(2)个矩阵是否相同的复杂度

先介绍一下二维哈希

二维哈希就是一维哈希的进化版

我们先进行一次哈希把(n)(m)列的数组变为(n)(1)列的数组

然后再进行一次哈希即可

for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            Hash[i][j] = Hash[i][j - 1] * mul_fir + a[i][j];

    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            Hash[i][j] += Hash[i - 1][j] * mul_sec;

然后我们要查询((x, y)(x_1, y_1))就为

Hash[x_1][y_1] - Hash[x_1][y_1 - 1] * pow_fir[y_1 - y + 1] - Hash[x - 1][y_1] * pow_sec[x_1 - x + 1] + Hash[x - 1][y - 1] * pow_fir[y_1 - y + 1] * pow_sec[x_1 - x + 1]

时间复杂度:(O(log~n * n ^ 4))

可以过

(ullet) 做法(3:)

我们照样考虑二维哈希

我们把第一个矩阵中边长为(k (k <= n))的所有正方形的哈希值与(k)都存入哈希表

最后在第二个矩阵中找出边长和值相同的最大矩阵即可

时间复杂度:(O(n ^ 3))

[Large exttt{Code}]

#include <bits/stdc++.h>

#define ull unsigned long long

const int MaxN = 50 + 10;

const int mul_fir = 9191891;
const int mul_sec = 6893911;
const int Mod = 999983;

using namespace std;

inline int read() {
    int cnt = 0, opt = 1;
    char ch = getchar();

    for (; ! isalnum(ch); ch = getchar())
        if (ch == '-')  opt = 0;
    for (; isalnum(ch); ch = getchar())
        cnt = cnt * 10 + ch - 48;

    return opt ? cnt : -cnt;
}

int n, m, ans;
ull AHash[MaxN][MaxN], BHash[MaxN][MaxN];
ull pow_fir[MaxN], pow_sec[MaxN];
int a[MaxN][MaxN], b[MaxN][MaxN];

struct Hash {
    int nxt;
    ull to_value;
    int to_k;
} table[MaxN * MaxN * MaxN];

int head[Mod + 10], tot;

inline ull calc(int x, int y, int X, int Y, int opt) {
    return opt == 1 ? AHash[X][Y] - AHash[x - 1][Y] * pow_sec[X - x + 1] - AHash[X][y - 1] * pow_fir[Y - y + 1] + AHash[x - 1][y - 1] * pow_sec[X - x + 1] * pow_fir[Y - y + 1] :
                      BHash[X][Y] - BHash[x - 1][Y] * pow_sec[X - x + 1] - BHash[X][y - 1] * pow_fir[Y - y + 1] + BHash[x - 1][y - 1] * pow_sec[X - x + 1] * pow_fir[Y - y + 1];
}

inline void insert(ull v, int k) {
    int u = v % Mod;
    table[++tot].nxt = head[u];
    head[u] = tot;
    table[tot].to_value = v;
    table[tot].to_k = k;
}

inline int query(ull v, int k) {
    int u = v % Mod;   
    for (int i = head[u]; i; i = table[i].nxt)
        if (table[i].to_k == k && table[i].to_value == v)
            return 1;
    return 0;
}

int main() {
    
    n = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            a[i][j] = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j)
            b[i][j] = read();
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            AHash[i][j] = AHash[i][j - 1] * mul_fir + a[i][j];

    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            AHash[i][j] += AHash[i - 1][j] * mul_sec;

    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            BHash[i][j] = BHash[i][j - 1] * mul_fir + b[i][j];

    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            BHash[i][j] += BHash[i - 1][j] * mul_sec;

    pow_fir[0] = 1, pow_sec[0] = 1;
    for (int i = 1; i <= MaxN - 10; ++ i)
        pow_fir[i] = pow_fir[i - 1] * mul_fir, pow_sec[i] = pow_sec[i - 1] * mul_sec;

    for (int k = 1; k <= n; ++ k)
        for (int i = 1; i <= n - k + 1; ++ i)
            for (int j = 1; j <= n - k + 1; ++ j)
                insert(calc(i, j, i + k - 1, j + k - 1, 1), k);
    for (int k = n; k >= 1; k --)
        for (int i = 1; i <= n - k + 1; ++ i)
            for (int j = 1; j <= n - k + 1; ++ j)
                if (query(calc(i, j, i + k - 1, j + k - 1, 0), k)) {
                    printf("%d
", k);
                    return 0;
                }
                    
    return 0;
}

以上是关于题解 P4398 [JSOI2008]Blue Mary的战役地图的主要内容,如果未能解决你的问题,请参考以下文章

P4254 [JSOI2008]Blue Mary开公司 (李超树)

bzoj1507 JSOI2008—Blue Mary的旅行

BZOJ 1567: [JSOI2008]Blue Mary的战役地图

1568: [JSOI2008]Blue Mary开公司

BZOJ 1567: [JSOI2008]Blue Mary的战役地图

BZOJ 1568: [JSOI2008]Blue Mary开公司(超哥线段树)