题目链接:http://codeforces.com/contest/1195/problem/E
题意:现在有一个 n ∗ m n*m n∗m的矩阵,给出矩阵每个点的计算公式,你需要找出这个矩阵所有大小为 a ∗ b a*b a∗b的子矩阵,然后将所有子矩阵中最小的数求和。
解题心得:
- 刚开始一看求矩阵最小值,算了一下大概二维线段树复杂度能过,然后哼哧哼哧写了半天,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;
}