TIOJ-1916

多筆測資,給一個$N\times N$的矩陣,每格有數字$a_{i,j}$,還有$Q$筆詢問。

對於每筆詢問,給定一個子矩陣範圍,輸出該子矩陣內的絕對多數或告知不存在。
絕對多數的定義是出現次數嚴格大於子矩陣大小的一半。

$N\le 2000, \sum N^2\le 1.25\times 10^7, \sum Q\le 70, a_{i, j}\le 10^9$


首先觀察到Q很小,雖然$N$真的很大,不過$\mathcal{O}(QN^2)$的複雜度其實是可行的。

所以對於每筆詢問,我們可以暴力跑遍一次子矩陣。
然而空間很緊,就算離散化再額外開個$4\times 10^6$的陣列都會MLE。
不過有個很經典的手段可以用$\mathcal{O}(1)$的空間找出絕對多數。

想像在一個擂台上,台上站著一個元素,這時加進一個新元素,如果該元素跟擂台上的元素一樣,就把血量給+1,否則血量-1。
如果血量已經歸零就下台,加進的那個元素上來,同時hp設為1。如果存在絕對多數,那最後站在擂台上的元素肯定會是絕對多數。
至於不存在絕對多數呢?既然已經知道了”可能的答案”,就再遍歷一次,計算那個答案的出現次數是否嚴格大於子矩陣大小的一半。
複雜度$\mathcal{O}(Q\sum N^2)$,空間複雜度$\mathcal{O}(N^2)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
using ll = int64_t;
using ull = uint64_t;
using ld = long double;
using uint = uint32_t;
const double EPS = 1e-8;
const int INF = 0x3F3F3F3F;
const ll LINF = 4611686018427387903;
const int MOD = 1e9+7;
/*--------------------------------------------------------------------------------------*/

int arr[2000][2000];

signed main() { EmiliaMyWife
int n;
while(cin >> n, n) {
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
cin >> arr[i][j];

int q;
cin >> q;
while(q--) {
int r1, r2, c1, c2;
cin >> r1 >> r2 >> c1 >> c2;
r2++; c2++;

int cur = 0, hp = 0;
for(int i = r1; i < r2; i++)
for(int j = c1; j < c2; j++) {
if(cur == arr[i][j])
hp++;
else {
if(hp)
hp--;
else
cur = arr[i][j], hp = 1;
}
}
int cnt = 0;
for(int i = r1; i < r2; i++)
for(int j = c1; j < c2; j++)
cnt += arr[i][j] == cur;
if(cnt > (r2 - r1) * (c2 - c1) / 2)
cout << cur << '\n';
else
cout << "-1\n";
}
}
}