思路:
- 题目给出一个n * m 的矩阵,其中矩阵中的值A(i,j) = lcm(i,j);试问矩阵中所以k * k的子矩阵中的max的和为多少。
- k * k矩阵最大值即max(每行max,每列max)。所以必须是某一行k个中最大值才有希望成为需要的值,先以此方法筛选一遍。
- 再找符合子矩阵中该列最大值的,找到最终需要相加的数,全都移动到右下方,让每一个子矩阵中符合条件的都在右下角。最后加起来所有的右下角数字。
- 筛的过程用单调队列,筛两次用二维单调队列,让最大的永远在队尾,只看最后是不是最大的这样可以优化,不去管别的顺序。
代码实现:
#include <bits/stdc++.h>
using namespace std;
const int N = 6000;
int n, m, k;
int q[N], a[N][N], b[N][N];
int main(){
cin >> n >> m >> k;
if(n > m) swap(n, m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
a[i][j] = i * j / __gcd(i, j);
for(int i = 1; i <= n; i ++){
int l = 1, r = 0;
for(int j = 1; j <= m; j ++){
while(l <= r && q[l] <= j - k) l ++;
while(l <= r && a[i][q[r]] <= a[i][j]) r --;
q[++ r]=j;
b[i][j] = a[i][q[l]];
}
}
for(int i = 1; i <= m; i ++){
int l = 1, r = 0;
for(int j = 1; j <= n; j ++){
while(l <= r && q[l] <= j - k) l ++;
while(l <= r && b[q[r]][i] <= b[j][i]) r --;
q[++ r] = j;
a[j][i] = b[q[l]][i];
}
}
long long ans = 0;
for(int i = k; i <= n; i ++)
for(int j = k; j <= m; j ++)
ans += a[i][j];
cout << ans << endl;
return 0;
}