题目链接:点击查看
题目大意:给出一个矩阵 A 的大小,规定其元素 A[ i ][ j ] = lcm( i , j ) ,再给出一个 k ,求所有大小为 k * k 的子矩阵中的最大值之和
题目分析:题目时限给了三秒,可以直接 n * m * logn 去求出矩阵 A ,但题解提供了一种可以线性求解 gcd 的方法,所以可以优化掉一层 log,在求出矩阵 A 后,可以对于每一行,利用单调队列维护区间最大值,mmax[ i ][ j ] 记录 A[ i ][ j - k ] : A[ i ][ j ] 的最大值,最后再利用单调队列,求解一下 mmax[ i - k ][ j ] : mmax[ i ][ j ] 的最大值就是子矩阵 ( i - k , j - k ) ~ ( i , j ) 的最大值了,区间维护最大值的代码可以参考经典例题:滑动窗口
另外这个题目有点卡内存,如果是 5000 * 5000 的数组的话,最多只能开两个,所以可以将 A 数组与 mmax 数组进行一个复用
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=5e3+100;
int g[N][N];
int mmax[N][N];//mmax[i][j]:max(maze[i][j-k]:maze[i][j])
struct Node
{
int val,id;
Node(int val,int id):val(val),id(id){}
};
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!g[i][j])
for(int k=1;k*i<=n&&k*j<=m;k++)
g[k*i][k*j]=k,mmax[k*i][k*j]=i*j*k;
for(int i=1;i<=n;i++)
{
deque<Node>q;
for(int j=1;j<=k-1;j++)
{
while(q.size()&&q.back().val<=mmax[i][j])//将比当前值小的数全删掉(尾部)
q.pop_back();
q.push_back(Node(mmax[i][j],j));
}
for(int j=k;j<=m;j++)
{
int left=j-k+1;
while(q.size()&&q.back().val<=mmax[i][j])//将比当前值小的数全删掉(尾部)
q.pop_back();
q.push_back(Node(mmax[i][j],j));
while(q.size()&&q.front().id<left)//将过期的值删掉(头部)
q.pop_front();
mmax[i][j]=q.front().val;
}
}
LL ans=0;
for(int j=k;j<=m;j++)
{
deque<Node>q;
for(int i=1;i<=k-1;i++)
{
while(q.size()&&q.back().val<=mmax[i][j])//将比当前值小的数全删掉(尾部)
q.pop_back();
q.push_back(Node(mmax[i][j],i));
}
for(int i=k;i<=n;i++)
{
int left=i-k+1;
while(q.size()&&q.back().val<=mmax[i][j])//将比当前值小的数全删掉(尾部)
q.pop_back();
q.push_back(Node(mmax[i][j],i));
while(q.size()&&q.front().id<left)//将过期的值删掉(头部)
q.pop_front();
ans+=q.front().val;
}
}
printf("%lld\n",ans);
return 0;
}