题目大意

给定整数n,m,k,构造一个n×m的矩阵A,其中Ai,j = lcm(i,j),第i行j列的数是i和j的最小公倍数。 求所有k×k个子矩阵中的最大值之和。

解题思路

先用尽可能快的操作将整张表求出来,接下来用单调队列。(附上大佬详解链接https://www.cnblogs.com/RealMadrid/articles/10599588.html
一次横排,一次竖排,记录每个区间中最大值的下标,顺便求和即可(这题要将代码讲的精细太头疼了)
用到双端队列deque,用法与queue相近,且添加了一些更舒服的操作,在头尾都可以删除或添加。(pop_back,pop_front,push_back,push_front等等)

AC代码

#include<bits/stdc++.h>
using namespace std;
int a[5010][5010],b[5010][5010],n,m,k;
long long ans; //ans用long long避免超限
deque<int> q;
int gcd(int x,int y)
{
    if(y==0) return x;
    return gcd(y,x%y);
}
int main()
{
    int i,j,t;
    scanf("%d%d%d",&n,&m,&k);
    for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
            a[i][j]=i*j/gcd(i,j);
    for(i=1;i<=n;i++)
    {
        t=0;
        while(!q.empty()) q.pop_back();
        for(j=1;j<=k;j++)
        {
            while(q.size() && a[i][q.back()]<=a[i][j]) q.pop_back();
            q.push_back(j);
        }
        t++,b[i][t]=a[i][q.front()];
        for(j=k+1;j<=m;j++)
        {
            while(q.size() && a[i][q.back()]<a[i][j]) q.pop_back();
            q.push_back(j);
            while(q.size() && q.front()<j-k+1) q.pop_front();
            t++,b[i][t]=a[i][q.front()];
        }
    }
    for(i=1;i<=t;i++)
    {
        while(!q.empty()) q.pop_back();
        for(j=1;j<=k;j++)
        {
            while(q.size() && b[q.back()][i]<=b[j][i]) q.pop_back();
            q.push_back(j);
        }
        ans+=b[q.front()][i];
        for(j=k+1;j<=n;j++)
        {
            while(q.size() && b[q.back()][i]<=b[j][i]) q.pop_back();
            q.push_back(j);
            while(q.size() && q.front()<j-k+1) q.pop_front();
            ans+=b[q.front()][i];
        }
    }
    printf("%lld\n",ans);
    return 0;
}