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

题目大意:给出两个m*m的地图,问两个地图的最大子正方形矩阵的边长是多大。

思路:先对两个矩阵hash,然后枚举最大长度,从大到小枚举。把第一个矩阵的所有情况插到哈希表中,然后查询第二个矩阵的所有情况。

记住哈希表中的那些数组一定要开大点。。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 60
#define RANGE 100100
using namespace std;
const unsigned long long BASE1 = 1333;
const unsigned long long BASE2 = 23333;
const int MO = 999997;

int m;
unsigned long long hash[MAX][MAX],_hash[MAX][MAX];
unsigned long long pow1[MAX],pow2[MAX];

struct HashSet{
    int head[MO],total;
    int next[RANGE];
    unsigned long long hash[RANGE];

    bool Check(unsigned long long h) {
        int x = h % MO;
        for(int i = head[x]; i; i = next[i])
            if(hash[i] == h)
                return true;
        return false;
    }
    void Insert(unsigned long long h) {
        int x = h % MO;
        next[++total] = head[x];
        hash[total] = h;
        head[x] = total;
    }
}set;

int main()
{
    cin >> m;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%lld",&hash[i][j]);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%lld",&_hash[i][j]);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j) {
            hash[i][j] += hash[i - 1][j] * BASE1;
            _hash[i][j] += _hash[i - 1][j] * BASE1;
        }
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j) {
            hash[i][j] += hash[i][j - 1] * BASE2;
            _hash[i][j] += _hash[i][j - 1] * BASE2;
        }
    pow1[0] = pow2[0] = 1;
    for(int i = 1; i <= m; ++i)
        pow1[i] = pow1[i - 1] * BASE1,pow2[i] = pow2[i - 1] * BASE2;
    int ans;
    for(ans = m; ans; --ans) {
        for(int i = ans; i <= m; ++i)
            for(int j = ans; j <= m; ++j) {
                unsigned long long h = hash[i][j];
                h -= hash[i - ans][j] * pow1[ans];
                h -= hash[i][j - ans] * pow2[ans];
                h += hash[i - ans][j - ans] * pow1[ans] * pow2[ans];
                set.Insert(h);
            }
        for(int i = ans; i <= m; ++i)
            for(int j = ans; j <= m; ++j) {
                unsigned long long h = _hash[i][j];
                h -= _hash[i - ans][j] * pow1[ans];
                h -= _hash[i][j - ans] * pow2[ans];
                h += _hash[i - ans][j - ans] * pow1[ans] * pow2[ans];
                if(set.Check(h)) {
                    cout << ans << endl;
                    return 0;
                }
            }
    }
    cout << 0 << endl;
    return 0;
}

时间: 2024-10-11 03:58:21

BZOJ 1567 JSOI 2008 Blue Mary的战役地图 二维hash的相关文章

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

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

BZOJ 1570 JSOI 2008 Blue Mary的旅行 网络流

题目大意 给出一个有向图,每天每人只能做一次飞机.现在给出起点,终点,和需要走的人数,还有每条航线的限制人数,问最少多少天最慢的人到达终点. 思路 很明显是网络流的模型,至于如何去验证,其实连二分都不用,枚举最少天数,然后每次加一层边进行验证就行了. CODE #define _CRT_SECURE_NO_WARNINGS #include <queue> #include <cstdio> #include <cstring> #include <iostrea

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

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

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

【字符矩阵哈希】【二分答案】【哈希表】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

[JSOI2008]Blue Mary的战役地图

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

题解 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)\),再枚举第二个矩阵的一个坐标

[BZOJ 1012] [JSOI 2008] 最大数maxnumber

1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5094  Solved: 2276[Submit][Status][Discuss] Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. 2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次