Fake Maxpooling
Fake Maxpooling
题意:
给你一个矩阵 矩阵的值为 行与列的坐标的lcm, 问子矩阵为k的所有子矩阵的最大值之和。
题解:
A:这题数据有问题吧!! 瞎搞都能过。
B:嗯嗯 比如 20 15 2 这组数据就可hack 30% 的人了, 这题正确的做法用单调队列或者滑动窗口, 是个模板题。
A:能解释下吗?
B:单调队列 先扫描每一行, 维护 递减, 然后判断 队列的首项 是否 > j - k 如果是 那么 这个子矩阵的行的最大值就是 \(mp[i][q.front()]\) 否则就删除首项。 然后再维护一边 列,就可求出每个子矩阵的最大值了。
A:没听懂!!!
B:那就看我的代码模拟一边。
A: 好的!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, k;
int mp[5007][5007];
int lcm(int x, int y) {
return x * y / __gcd(x, y);
}
int maxn[5007][5007];
deque<int>q;
int main () {
scanf("%d %d %d", &n, &m, &k);
ll sum = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
mp[i][j] = lcm(i, j);
}
}
for (int i = 1; i <= n; i++) {
q.clear();
for (int j = 1; j <= m; j++) {
while (!q.empty() && mp[i][q.front()] < mp[i][j]) {
q.pop_back();
}
q.push_back(j);
while(!q.empty() && q.front() <= j - k) {
q.pop_front();
}
maxn[i][j] = mp[i][q.front()];
}
}
for (int i = 1; i <= m; i++) {
q.clear();
for (int j = 1; j <= n; j++) {
while (!q.empty() && maxn[q.front()][i] < maxn[j][i]) {
q.pop_back();
}
q.push_back(j);
while(!q.empty() && q.front() <= j - k) {
q.pop_front();
}
mp[j][i] = maxn[q.front()][i];
}
}
ll ans = 0;
for (int i = k; i <= n; i++) {
for (int j = k; j <= m; j++) {
ans += mp[i][j];
}
}
printf("%lld\n", ans);
}