题目传送门
题意:
一个 的矩阵,你有两个数 和 。
表示以 为左上角大小为 的子矩阵里面的数的最小值。
让你计算 。
题解:
表示以 为左上角大小为 的子矩阵里面的数的最小值。
然后这个其实就等价于求连续 个数的最小值。可以想到是优先队列。
然后对于 这个矩阵的每列都用若干次优先队列,累加即可。
感受:
本来用线段树搞,T了。
然后想了想,发现是单调队列。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 3005 ;
const int inf = 0x3f3f3f3f ;
int n , m , a , b ;
int g0 , x , y , z ;
int g[maxn][maxn] ;
int c[maxn][maxn] ;
int q[maxn] ;
int main()
{
scanf("%d%d%d%d" , &n , &m , &a , &b) ;
scanf("%d%d%d%d" , &g0 , &x , &y , &z) ;
int temp = g0 ;
for(int i = 1 ; i <= n ; i ++)
for(int j = 1 ; j <= m ; j ++)
g[i][j] = temp , temp = int((ll(temp) * x + y) % z) ;
for(int i = 1 ; i <= n ; i ++)
{
int l = 1 , r = 0 ;
for(int j = 1 ; j <= b ; j ++)
{
while(l <= r && g[i][q[r]] > g[i][j]) r -- ;
q[++ r] = j ;
}
c[i][1] = g[i][q[l]] ;
for(int j = b + 1 ; j <= m ; j ++)
{
while(l <= r && q[l] < j - b + 1) l ++ ;
while(l <= r && g[i][q[r]] > g[i][j]) r -- ;
q[++ r] = j ;
c[i][j - b + 1] = g[i][q[l]] ;
}
}
ll ans = 0 ;
for(int j = 1 ; j + b - 1 <= m ; j ++)
{
int l = 1 , r = 0 ;
for(int i = 1 ; i <= a ; i ++)
{
while(l <= r && c[q[r]][j] > c[i][j]) r -- ;
q[++ r] = i ;
}
ans += c[q[l]][j] ;
for(int i = a + 1 ; i <= n ; i ++)
{
while(l <= r && q[l] < i - a + 1) l ++ ;
while(l <= r && c[q[r]][j] > c[i][j]) r -- ;
q[++ r] = i ;
ans += c[q[l]][j] ;
}
}
printf("%lld\n" , ans) ;
return 0 ;
}