2020牛客暑假多校训练营(第二场)F-Fake Maxpooling
题意: 给定矩阵(A),(A[i,j]=operatorname{lcm}(i,j))。求大小为(k imes 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<<"
";
return 0;
}