Codeforces Round #574 (Div. 2) E. OpenStreetMap(处理二维单调队列)

题目链接:http://codeforces.com/contest/1195/problem/E

题意:现在有一个 n ∗ m n*m nm的矩阵,给出矩阵每个点的计算公式,你需要找出这个矩阵所有大小为 a ∗ b a*b ab的子矩阵,然后将所有子矩阵中最小的数求和。

解题心得:

  • 刚开始一看求矩阵最小值,算了一下大概二维线段树复杂度能过,然后哼哧哼哧写了半天,MLE,也是蠢了。
  • 其实就用过一个单调队列维护一下就好了,只不过看到用单调队列处理矩阵最小值突然没反应过来。


    #include <bits/stdc++.h>
    using namespace std;
    const long long maxn = 3010;
    typedef long long ll;
     
    ll node[maxn][maxn], n, m, a, b, X, Y, z, g0, num[maxn][maxn], pos[maxn*maxn];
     
    void init() {
        scanf("%lld%lld%lld%lld%lld%lld%lld%lld", &n, &m, &a, &b, &g0, &X, &Y, &z);
        for(ll i=1;i<=n;i++) {
            for(ll j=1;j<=m;j++) {
                num[i][j] = g0;
                g0 = (1ll*g0*X + Y) % z;
            }
        }
    }
     
    int main() {
    //    freopen("1.in.txt", "r", stdin);
        init();
     
        ll tail, head;
        for(ll j=1;j<=m;j++) {
            tail = 1, head = 2;
            for(ll i=1;i<=n;i++) {
                while(tail >= head && i-a >= pos[head]) head++;
                while(tail >= head && num[i][j] <= num[pos[tail]][j]) tail--;
                pos[++tail] = i;
                node[i][j] = num[pos[head]][j];
            }
        }
     
        ll sum = 0;
        for(ll i=a;i<=n;i++) {
            tail = 1, head =2;
            for(ll j=1;j<=m;j++) {
                while(tail >= head && j-b >= pos[head]) head++;
                while(tail >= head && node[i][j] <= node[i][pos[tail]]) tail--;
                pos[++tail] = j;
                if(j >= b)
                    sum += node[i][pos[head]];
            }
        }
     
        printf("%lld\n", sum);
        return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值