F. Fake Maxpooling (二维单调队列)2020牛客暑期多校训练营(第二场)

传送门

在这里插入图片描述
在这里插入图片描述
思路:

  • 题目给出一个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;
}

猜你喜欢

转载自blog.csdn.net/Satur9/article/details/107570816