牛客暑期多校训练营F Fake Maxpooling

第二场F题在这里插入图片描述

题目大意:
为有一个由A(i,j)=lcm(i,j),组成的矩阵,需要找出所有该矩阵中每个k×k大小的子矩阵中最大值的和

样例:
在这里插入图片描述

题目思路:
使用单调队列处理每行连续k个数的最大值得到一个新的二维数组,得到答案后再使用单调队列处理新数组中每列连续k个数,最终得到含有每个k*k矩阵最大值的数组,相加求和
单调队列中存的是这连续k个数字的下标,这样既方便滑动也不影响记录最大值


单调队列是干什么的?
单调队列可以保证,对于任何一个数而言,只会在队列中出现一次,一旦这个数对于最后答案没有贡献了,就会及时地将它删除.
一般来说,入队和出队操作满足以下两点.

  1. 入队操作:对于一个点而言,如果说它加入队列后满足队列的单调性质,那么我们就可以入队.
  2. 出队操作:对于一个点而言,如果说新加入的点,比它更加具有潜力,潜力一般指(拓展性更强,生存能力更高,节点入队时间短.)

此段来源于https://www.acwing.com/blog/content/150/
关于单调队列的详情可在此链接里了解


#include<iostream>
using namespace std;
typedef long long ll;
int q[10000],a[5005][5005],b[5005][5005],h,e,n,m,k;
ll ans=0;
int gcd(int a,int b) 
{
 return b==0?a:gcd(b,a%b);
}
int main()
{
    cin>>n>>m>>k; 
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=i*j/gcd(i,j);//首先确定该矩阵 
//计算矩阵每行的连续k个数的最大值 
    for(int i=1;i<=n;i++)
    {
        h=1;
        e=1;
        for(int j=1;j<=m;j++)
  { 
            while(e-h>0&&q[h]<=j-k) 
    h++;   
            while(e-h>0&&a[i][q[e-1]]<=a[i][j]) 
    e--;
            q[e++]=j;
    // 此时的 q[e] 中就是当前连续的 k个值中最大值的下标 
            b[i][j]=a[i][q[h]];
        }
    }
//计算每列中的连续k个数的最大值    
    for(int j=1;j<=m;j++)
 {
        h=1;
  e=1;
        for(int i=1;i<=n;i++)
  {
            while(e-h>0&&q[h]<=i-k) 
    h++;
            while(e-h>0&&b[q[e-1]][j]<=b[i][j]) 
    e--;
            q[e++]=i;
            b[i][j]=b[q[h]][j];
//此时的 q[e] 就是当前这个 k*k的矩阵中的最大值了    
        }
    }
    for(int i=k;i<=n;i++)
     for(int j=k;j<=m;j++)
      ans=ans+b[i][j];
    cout<<ans<<endl;
    return 0;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值