2020牛客暑期多校训练营(第二场)未完待续......

F. Fake Maxpooling

题目:
在这里插入图片描述
在这里插入图片描述
题目大意:
输入n,m,k。矩阵的尺寸为nm,其中每一个元素为A[i][j] = lcm( i , j )。从中找出所有kk的子矩阵中元素最大的数之和。
题解:
时间为3s,O( n m nm nm)的算法和O( n m l o g n nmlogn nmlogn)的算法。

  1. 构建矩阵:朴素算法O( n m l o g n nmlogn nmlogn),直接暴力就行。
  2. O( n m nm nm)构建矩阵:类似于埃氏筛的写法:
    出题人巨巨的写法
for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            if (!Gcd[i][j]) //没有被筛过,则证明i,j互质
                for (int z = 1; z * i <= n && z * j <= m; z++)//z为扩大的倍数
                {
                    Gcd[i * z][j * z] = z;
                    A[i * z][j * z] = i * j * z;//矩阵元素计算
                }
  1. 查找最大值:二维的滑动窗口,我们用单调队列进行即可。
    1. 先按每一列or行进行一维的单调队列的查找并存入新的数组中。
    2. 然后再用新的数组进行另外每一行or列进行一维单调队列即可。
    3. 坑点:注意我们再进行另外一维的时候要用新的数组,新的数组要从列标or行标开始循环。

本人的ACcode:

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-07-13 22:54:45
 * @CSDN blog: https://blog.csdn.net/acm_durante
 * @E-mail: 1055323152@qq.com
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
const double PI = acos(-1.0);
int n, m, k;
int a[5005][5005];
int b[5005][5005];
int que[5005];
ll ans = 0;
void solvej(int i)
{
    int l = 1, r = 0;
    rep(j, 1, m)
    {
        while (r >= l && a[i][que[r]] <= a[i][j])
            --r;
        que[++r] = j;
        while (r >= l && que[l] + k <= j)
            ++l;
        if (j >= k)
            b[i][j] = a[i][que[l]];
    }
}
void solvei(int j)
{
    int l = 1, r = 0;
    rep(i, 1, n)
    {
        while (r >= l && b[que[r]][j] <= b[i][j])
            --r;
        que[++r] = i;
        while (r >= l && que[l] + k <= i)
            ++l;
        if (i >= k)
            ans += b[que[l]][j];
    }
}
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    if (n > m)
        swap(n, m);
    rep(i, 1, n)
    {
        rep(j, i, m)
        {
            a[i][j] = a[j][i] = i * j / __gcd(i, j);
        }
    }
    rep(i, 1, n) //先对每一行进行单调队列处理
        solvej(i);
    rep(j, k, m) //对新数组每一列的单调队列处理,并求和
        solvei(j);
    printf("%lld\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值