[JSOI2008]Blue Mary的战役地图

嘟嘟嘟

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

~~求一个矩阵的哈希值就是每一行的哈希值之和~~

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("")
13 #define space putchar(‘ ‘)
14 #define Mem(a) memset(a, 0, sizeof(a))
15 typedef long long ll;
16 typedef unsigned long long ull;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const int eps = 1e-8;
20 const int maxn = 55;
21 const ull base = 19260817;    //请无视
22 inline ll read()
23 {
24     ll ans = 0;
25     char ch = getchar(), last = ‘ ‘;
26     while(!isdigit(ch)) {last = ch; ch = getchar();}
27     while(isdigit(ch)) {ans = ans * 10 + ch - ‘0‘; ch = getchar();}
28     if(last == ‘-‘) ans = -ans;
29     return ans;
30 }
31 inline void write(ll x)
32 {
33     if(x < 0) x = -x, putchar(‘-‘);
34     if(x >= 10) write(x / 10);
35     putchar(x % 10 + ‘0‘);
36 }
37
38 int n, a[2][maxn][maxn];
39 ull has[2][maxn][maxn];
40 ull f[maxn], b[maxn * maxn];
41 int cnt = 0;
42
43
44 ull calc(int x, int y, int l, bool flag)
45 {
46     ull ret = 0;
47     for(int i = x; i <= x + l - 1; ++i) ret += has[flag][i][y + l - 1] - has[flag][i][y - 1] * f[l];
48     return ret;
49 }
50 bool judge(int x)
51 {
52     cnt = 0;
53     for(int i = 1; i <= n - x + 1; ++i)
54         for(int j = 1; j <= n - x + 1; ++j)
55             b[++cnt] = calc(i, j, x, 0);
56     sort(b + 1, b + cnt + 1);
57     for(int i = 1; i <= n - x + 1; ++i)
58         for(int j = 1; j <= n - x + 1; ++j)
59         {
60             ull ha = calc(i, j, x, 1);
61             if(*lower_bound(b + 1, b +cnt + 1, ha) == ha) return 1;
62         }
63     return 0;
64 }
65
66 int main()
67 {
68     n = read();
69     for(int k = 0; k <= 1; k++)
70         for(int i = 1; i <= n; ++i)
71             for(int j = 1; j <= n; ++j) a[k][i][j] = read();
72     f[0] = 1;
73     for(int i = 1; i <= n; ++i) f[i] = f[i - 1] * base;
74     for(int k = 0; k <= 1; ++k)
75         for(int i = 1; i <= n; ++i)
76             for(int j = 1; j <= n; ++j) has[k][i][j] = has[k][i][j - 1] * base + a[k][i][j];
77     int L = 1, R = n;
78     while(L + 1 < R)
79     {
80         int mid = (L + R) >> 1;
81         if(judge(mid)) L = mid;
82         else R = mid - 1;
83     }
84     write(judge(L + 1) ? L + 1 : L); enter;
85     return 0;
86 }

原文地址:https://www.cnblogs.com/mrclr/p/9549230.html

时间: 2024-10-06 05:47:48

[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

题解 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 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>

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,则

数据结构(线段树):BZOJ 1568 [JSOI2008]Blue Mary开公司

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