codeforces1195E 2100分單調隊列

題目傳送門

題意:

一個 \dpi{150}n*m 的矩陣,你有兩個數 a 和 b 。

f(i,j) 表示以 (i,j) 爲左上角大小爲 a*b 的子矩陣裏面的數的最小值。 

讓你計算 \sum_{i=1}^{n-a+1} \sum_{j=1}^{m-b+1} f(i,j) 。

數據範圍:1 \leqslant n,m \leqslant 3000 , 1 \leqslant a \leqslant n , 1 \leqslant b \leqslant m 。

題解:

c[i][j] 表示以 (i,j) 爲左上角大小爲 1*b 的子矩陣裏面的數的最小值。 

然後這個其實就等價於求連續 b 個數的最小值。可以想到是優先隊列。

然後對於 c 這個矩陣的每列都用若干次優先隊列,累加即可。

感受:

本來用線段樹搞,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 ;
}

 

發佈了231 篇原創文章 · 獲贊 12 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章