2020牛客暑期多校训练营(第二场) F Fake Maxpooling

思路:这题本来是要卡一手log,但数据水了,除去求gcd,就二维单调队列裸题

#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> pii;
const int maxn = 5e3 + 100;

int gcd(int a, int b){
    return b == 0 ? a : gcd(b, a % b);
}
int que[maxn * 100];
int a[maxn][maxn];
int g[maxn][maxn];

int main(int argc, char const *argv[])
{
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i++){
        int le = 1, ri = 0;
        for(int j = 1; j < k; j++){
            g[i][j] = i * j / gcd(i, j);
            while(le <= ri && g[i][j] >= g[i][que[ri]]) ri--;
            que[++ri] = j;
        }
        for(int j = k; j <= m; j++){
            g[i][j] = i * j / gcd(i, j);
            while(le <= ri && g[i][j] >= g[i][que[ri]]) ri--;
            que[++ri] = j;
            a[i][j - k + 1] = g[i][que[le]];
            while(j - que[le] + 1 >= k && le <= ri) {
                le++;
            }
        }
    }

    for(int j = 1; j <= m - k + 1; j++){
        int le = 1, ri = 0;
        for(int i = 1; i < k; i++){
            while(le <= ri && a[i][j] >= a[que[ri]][j]) ri--;
            que[++ri] = i;
        }
        for(int i = k; i <= n; i++){
            while(le <= ri && a[i][j] >= a[que[ri]][j]) ri--;
            que[++ri] = i;
            a[i - k + 1][j] = a[que[le]][j];
            while(i - que[le] + 1 >= k && le <= ri) le++;
        }
    }
    LL ans = 0;
    for(int i = 1; i <= n - k + 1; i++){
        for(int j = 1; j <= m - k + 1; j++){
            ans += a[i][j];
        }
    }
    printf("%lld\n", ans);
    return 0;
}
posted @ 2020-07-14 21:52  从小学  阅读(97)  评论(0编辑  收藏  举报