Codeforces Round #574 (Div. 2) E - OpenStreetMap (单调队列,求子矩阵最小值的和)

E. OpenStreetMap

Seryozha conducts a course dedicated to building a map of heights of Stepanovo recreation center. He laid a rectangle grid of size n×mn×mcells on a map (rows of grid are numbered from 11 to nn from north to south, and columns are numbered from 11 to mm from west to east). After that he measured the average height of each cell above Rybinsk sea level and obtained a matrix of heights of size n×mn×m. The cell (i,j)(i,j) lies on the intersection of the ii-th row and the jj-th column and has height hi,jhi,j.

Seryozha is going to look at the result of his work in the browser. The screen of Seryozha's laptop can fit a subrectangle of size a×ba×b of matrix of heights (1≤a≤n1≤a≤n, 1≤b≤m1≤b≤m). Seryozha tries to decide how the weather can affect the recreation center — for example, if it rains, where all the rainwater will gather. To do so, he is going to find the cell having minimum height among all cells that are shown on the screen of his laptop.

Help Seryozha to calculate the sum of heights of such cells for all possible subrectangles he can see on his screen. In other words, you have to calculate the sum of minimum heights in submatrices of size a×ba×b with top left corners in (i,j)(i,j) over all 1≤i≤n−a+11≤i≤n−a+1 and 1≤j≤m−b+11≤j≤m−b+1.

Consider the sequence gi=(gi−1⋅x+y)modzgi=(gi−1⋅x+y)modz. You are given integers g0g0, xx, yy and zz. By miraculous coincidence, hi,j=g(i−1)⋅m+j−1hi,j=g(i−1)⋅m+j−1 ((i−1)⋅m+j−1(i−1)⋅m+j−1 is the index).

Input

The first line of the input contains four integers nn, mm, aa and bb (1≤n,m≤30001≤n,m≤3000, 1≤a≤n1≤a≤n, 1≤b≤m1≤b≤m) — the number of rows and columns in the matrix Seryozha has, and the number of rows and columns that can be shown on the screen of the laptop, respectively.

The second line of the input contains four integers g0g0, xx, yy and zz (0≤g0,x,y<z≤1090≤g0,x,y<z≤109).

Output

Print a single integer — the answer to the problem.

Example

input

Copy

3 4 2 1
1 2 3 59

output

Copy

111

Note

The matrix from the first example:

 

题意:有一种矩阵的构造方式,然后要求的是矩阵中的  大小为 a * b 的子矩阵的最小值  的和。

思路:一开始并没有算空间,用树套树写了一下,才发现空间不够用。

发现单调队列可写。开3000个单调队列,用来维护列,也就是列宽为 b 时的最小值,第 i 个单调队列对应第 i 行。求答案时,很容易想到再开一个单调队列,维护竖着行宽为 a 时的最小值,每一次都查询队头求和即可。

Code:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const int maxn = 3100;
const int inf = 0x3f3f3f3f;
int g[maxn * maxn];
int n,m,a,b;
LL x,y,z;
struct xx{
    int x,id;
    xx(int x = 0,int id = 0):
        x(x),id(id){}
};
deque<xx>de[maxn],AnsDe;

void Push(deque<xx> &tmp,int val,int index){
    if(tmp.empty() || tmp.back().x <= val)
        tmp.pb(xx(val,index));
    else {
        while(!tmp.empty() && tmp.back().x > val)
            tmp.pop_back();
        tmp.pb(xx(val,index));
    }
}

int main() {
    scanf("%d%d%d%d",&n,&m,&a,&b);
    scanf("%d%lld%lld%lld",&g[0],&x,&y,&z);
    LL tmp;
    for(int i = 1;i <= (n + 10) * (m + 10);++ i){
        tmp = (((LL)g[i - 1] * x % z) + y) % z;
        g[i] = tmp;
    }
    for(int i = 1;i <= n;++ i){
        for(int j = 1;j < b;++ j){
            Push(de[i],g[(i - 1) * m + j - 1],j);
        }
    }
    LL ans = 0;
    for(int j = b;j <= m;++ j){
        while(!AnsDe.empty()) AnsDe.pop_front();
        for(int i = 1;i <= n;++ i){
            Push(de[i],g[(i - 1) * m + j - 1],j);
            while(de[i].front().id <= j - b) de[i].pop_front();
//            debug(de[i].front().x);
            Push(AnsDe,de[i].front().x,i);
            while(AnsDe.front().id <= i - a) AnsDe.pop_front();
            if(i >= a) ans += AnsDe.front().x;
        }
    }
    cout << ans << endl;
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值