zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第二场) F-Fake Maxpooling

    链接

    F-Fake Maxpooling

    题意

    一个(n*m)的矩阵A,每个元素(A_{i,j})的值是lcm(i, j),求所有(k*k)子矩阵中最大元素的和

    思路

    每行求出所有长度为k的区间中的最大值,再对求出的行最大值矩阵的每列进行同样的操作,最后求和。
    至于区间最大值,可以用单调队列求解,但是不知道为啥队友t了,可能比赛用的机子波动吧

    代码

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define ms(a) memset(a, 0, sizeof(a))
    #define repu(i, a, b) for (int i = a; i < b; i++)
    #define repd(i, a, b) for (int i = a; i > b; i--)
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    
    const int M = int(1e3) * 5 + 5;
    const int mod = int(1e9) + 7;
    
    inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
    
    int a[M][M];
    int ma[M][M];
    deque<int> q;
    int main() {
        int n, m, k;
        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);
            }
        }
    
        for (int i = 1; i <= n; i++) {
            while (!q.empty()) q.pop_back();
            q.push_back(0);
            for (int j = 1; j < k; j++) {
                while (q.size() && a[i][q.front()] <= a[i][j]) {
                    q.pop_back();
                }
                q.push_back(j);
            }
            for (int j = k; j <= m; j++) {
                while (q.size() && q.front() <= j - k) {
                    q.pop_front();
                }
                while (q.size() && a[i][q.back()] <= a[i][j]) {
                    q.pop_back();
                }
                q.push_back(j);
                ma[i][j] = max(ma[i][j], a[i][q.front()]);
            }
        }
    
        ll ans = 0;
        for (int j = k; j <= m; j++) {
            while (!q.empty()) {
                q.pop_back();
            }
            q.push_back(0);
            for (int i = 1; i < k; i++) {
                while (q.size() && ma[q.front()][j] <= ma[i][j]) {
                    q.pop_back();
                }
                q.push_back(i);
            }
            for (int i = k; i <= n; i++) {
                while (q.size() && q.front() <= i - k) {
                    q.pop_front();
                }
                while (q.size() && ma[q.front()][j] <= ma[i][j]) {
                    q.pop_back();
                }
                q.push_back(i);
                ans += ma[q.front()][j];
            }
        }
        cout << ans << endl;
        return 0;
    }
    
    

    备注

    据说用__gcd会t,建议家中常备递归式gcd
    这种暴力求A的方法复杂度是(O(nmlog_n))的,题解给了个(O(nm))的解法,值得学习

    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
            if (!Gcd[i][j])
                for (int k = 1; k * i <= n && k * j <= m; k ++)
                    Gcd[k * i][k * j] = k, A[k * i][k * j] = i * j * k;
    

    类似一个筛,枚举所有的gcd

  • 相关阅读:
    2019.6.30 Spring注解 bean后置处理器和属性赋值
    2019.6.29 Spring注解-Bean的注册
    2019.6.28 Spring注解
    boost基础环境搭建
    动态规划入门一:钢条切割问题
    《剑指offer》读书笔记
    字符串的全排列
    西山居递归面试题
    常见的数据结构
    832. Flipping an Image
  • 原文地址:https://www.cnblogs.com/harutomimori/p/13327005.html
Copyright © 2011-2022 走看看