第二场F题
题目大意:
为有一个由A(i,j)=lcm(i,j),组成的矩阵,需要找出所有该矩阵中每个k×k大小的子矩阵中最大值的和
样例:
题目思路:
使用单调队列处理每行连续k个数的最大值得到一个新的二维数组,得到答案后再使用单调队列处理新数组中每列连续k个数,最终得到含有每个k*k矩阵最大值的数组,相加求和
单调队列中存的是这连续k个数字的下标,这样既方便滑动也不影响记录最大值
单调队列是干什么的?
单调队列可以保证,对于任何一个数而言,只会在队列中出现一次,一旦这个数对于最后答案没有贡献了,就会及时地将它删除.
一般来说,入队和出队操作满足以下两点.
- 入队操作:对于一个点而言,如果说它加入队列后满足队列的单调性质,那么我们就可以入队.
- 出队操作:对于一个点而言,如果说新加入的点,比它更加具有潜力,潜力一般指(拓展性更强,生存能力更高,节点入队时间短.)
此段来源于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;
}