返回顶部

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

2020牛客暑假多校训练营(第二场)F-Fake Maxpooling

题意: 给定矩阵\(A\),\(A[i,j]=\operatorname{lcm}(i,j)\)。求大小为\(k\times k\)的所有子矩阵中的最大值的和。

两次单调队列,第一次遍历所有的行,得到每一行中的一维最大值记录在数组\(B\)。第二次遍历数组\(B\)得到最后每一个子矩阵的最大值。比赛的时候暴力算了一遍初始矩阵怕过不了丢给队友直接就过了。。。迷惑行为。官方题解说是要有优化。扒了中学生大佬的代码过来,计算初始矩阵也有一定优化,官方题解优化的更加彻底一点。但是都能过,无所谓了。

Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=5050;
typedef long long ll;
int a[maxn][maxn],q[maxn],b[maxn][maxn];
int main(){
    int n,m,k;
    cin>>n>>m>>k;
    if(n>m)swap(n,m);
    for(int i=1;i<=n;i++){
        for(int j=i;j<=m;j++){
            a[i][j]=i*j/__gcd(i,j);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++)a[i][j]=a[j][i];
    }
    for(int i=1;i<=n;i++){
        int l=1,r=0;
        for(int j=1;j<=m;j++){
            while(l<=r&&a[i][q[r]]<=a[i][j])r--;
            q[++r]=j;
            while(l<=r&&q[l]<=j-k)l++;
            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&&b[q[r]][i]<=b[j][i])r--;
            q[++r]=j;
            while(l<=r&&q[l]<=j-k)l++;
            a[j][i]=b[q[l]][i];
        }
    }
    ll ans=0;
    for(int i=k;i<=n;i++)for(int j=k;j<=m;j++)ans+=a[i][j];
    cout<<ans<<"\n";
    return 0;
}
posted @ 2020-07-13 20:49  Charles1999  阅读(157)  评论(0编辑  收藏  举报