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

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:

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

 

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

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

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

Code:

#include
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair
#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){}
};
dequede[maxn],AnsDe;

void Push(deque &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;
}

 

你可能感兴趣的:(#,codeforces,#,单调队列)