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

题目链接:LuoguP4398

二维哈希 \(+\) 哈希表

\[\Large\texttt{description}\]

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

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

数据范围 \(n \leq 50\)

\[\Large\texttt{Solution}\]

\(\bullet\) 做法\(1:\)

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

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

也可以二分\(k\)

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

吸氧即可过

\(\bullet\) 做法\(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)\)

可以过

\(\bullet\) 做法\(3:\)

我们照样考虑二维哈希

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

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

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

\[\Large\texttt{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\n", k);
                    return 0;
                }

    return 0;
}

原文地址:https://www.cnblogs.com/chz-hc/p/12221311.html

时间: 2024-08-01 06:02:00

题解 P4398 【[JSOI2008]Blue Mary的战役地图】的相关文章

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

二次联通门 : BZOJ 1567: [JSOI2008]Blue Mary的战役地图 /* BZOJ 1567: [JSOI2008]Blue Mary的战役地图 社会我栋哥 人怂P话多 暴力能A题 正解能WA0 */ #include <cstdio> #include <iostream> #define rg register inline void read (int &n) { rg char c = getchar (); for (n = 0; !isdig

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

此题时限10秒,顿时惊呆,想到一个n^5解法,果断去写. 用f[i1][j1][i2][j2]表示从a矩阵的(i1,j1)和b矩阵的(i2,j2)开始哪一行有多少相同的. 然后再枚举i1,i2,j1,j2然后判断有几行. 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int n; 5 int ans=0; 6 long long a[60][60],b[60][60]; 7 int f[60][60

【字符矩阵哈希】【二分答案】【哈希表】bzoj1567 [JSOI2008]Blue Mary的战役地图

引用题解:http://hzwer.com/5153.html 当然,二分可以换成哈希表. #include<cstdio> #include<iostream> #include<cstring> using namespace std; #define MOD 2501 typedef unsigned long long ull; const ull seed1=3659,seed2=1789; ull sum[51][51],sum2[51][51],v[MOD

BZOJ 1567 JSOI2008 Blue Mary的战役地图 Hash+二分

题目大意:给定两个矩阵,求最大公共子正方形边长 首先二分答案 然后Check的时候先把A矩阵的所有边长为x的子正方形存在哈希表里 然后枚举B矩阵的每个子正方形查找 注意二维哈希的时候横竖用的两个BASE不能一样 否则当两个矩阵关于对角线对称的时候会判断为相等 尼玛我的哈希表居然比map慢--不活了 #include<map> #include<cstdio> #include<cstring> #include<iostream> #include<a

[JSOI2008]Blue Mary的战役地图

嘟嘟嘟 当看到n <= 50 的时候就乐呵了,暴力就行了,不过最暴力的方法是O(n7)--然后加一个二分边长达到O(n6logn),然后我们接着优化,把暴力比对改成O(1)的比对hash值,能达到O(n5logn),到勉强能过--不过我们还可以在优化一下,把第一个矩阵中所有边长为 l 的子矩阵的hash值都存到一个数组中,然后sort一下,接着我们在枚举第二个矩阵的子矩阵,然后在数组中用lower_bound的查询就行.这样的话复杂度应该是O(n3log(n2) * logn)了. ~~求一个矩

BZOJ 1567 JSOI 2008 Blue Mary的战役地图 二维hash

题目大意:给出两个m*m的地图,问两个地图的最大子正方形矩阵的边长是多大. 思路:先对两个矩阵hash,然后枚举最大长度,从大到小枚举.把第一个矩阵的所有情况插到哈希表中,然后查询第二个矩阵的所有情况. 记住哈希表中的那些数组一定要开大点.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 60 #define RA

BZOJ 1567 Blue Mary的战役地图(二维hash+二分)

题意: 求两个矩形最大公共子正方形.(n<=50) 范围这么小可以枚举子正方形的边长.那么可以对这个矩形进行二维hash,就可以在O(1)的时候求出任意子矩形的hash值.然后判断这些正方形的hash值有没有相同的 部分就行了.可以用二分来判断. 需要注意的是行和列乘的hash种子值需要不同的质数,否则可能出现冲突. 时间复杂度O(n^3logn). # include <cstdio> # include <cstring> # include <cstdlib>

[JSOI2008]Blue Mary的旅行

[**[JSOI2008]Blue Mary的旅行**](https://www.luogu.org/problem/P4400) #### 题解: 看见这些人流动的过程,我们很容易想到网络流,看见最早到达时间,~~我们很容易想到费用流~~. 我们可以看出题目中所说的z对应着网络流中的容量,但是一天过后又重新可以使用这一条边,我们显然不能直接跑网络流,对于一个人,它的贡献为$1$,所以这道题可以转化为一个最大流的模型. 考虑整个问题,朝贪心的方面去想,要尽量的选择一条$s$到$t$的最短路径,选

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

1568: [JSOI2008]Blue Mary开公司 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1080  Solved: 379[Submit][Status][Discuss] Description Input 第一行 :一个整数N ,表示方案和询问的总数. 接下来N行,每行开头一个单词“Query”或“Project”. 若单词为Query,则后接一个整数T,表示Blue Mary询问第T天的最大收益. 若单词为Project,则