Codeforces 1195E OpenStreetMap 单调栈

思路:对于某一行来说,我们只需要维护[1,b],[2,b+1],[3,b+2]...[m-b+1,m]的最小值,然后再对列进行维护即可,最后的矩阵的和就是答案。如何维护[1,b],[2,b+1],[3,b+2]...[m-b+1,m]的最小值呢?我一开始的思路是把区间的数字放到multiset中,然后set.begin()存的就是最小值,每次区间向右移,则增加新元素,删掉之前区间最左边的元素,但是这样做的复杂度是n*m*log,于是TLE。于是换了单调栈。对于某一行,我们维护一个长度最大为b的单调递增栈,每次遇到一个元素则把这个元素放入栈中,同时,栈中比此元素大的数字则会被pop出丢弃掉,最后答案就是栈底元素的值。处理完行之后,再处理每一列即可。这时,c[i][j]的值是以(i,j)为右下角,长宽各为a和b的矩形的最小值。

 

 

#include<iostream>
#include<cstdio>
#include<set>
using namespace std;
const int MAXN=3002;
int a[MAXN][MAXN];
int b[MAXN][MAXN];
int c[MAXN][MAXN];
int q[MAXN];
int n,m;
int aa,bb;
typedef long long ll;
ll g,x,y,z;
 
int main(){
	
	scanf("%d%d%d%d",&n,&m,&aa,&bb);
	scanf("%lld%lld%lld%lld",&g,&x,&y,&z);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			a[i][j]=g;
			g=(g*x+y)%z;
		}
	}
	for(int i=1;i<=n;i++){
		int l=1,r=0;
		for(int j=1;j<=m;j++){
			if(l<=r&&j-q[l]+1>bb){
				l++;
			}
			while(l<=r&&a[i][j]<=a[i][q[r]])r--;
			q[++r]=j;
			b[i][j]=a[i][q[l]];
		}
	}
	for(int j=1;j<=m;j++){
		int l=1,r=0;
		for(int i=1;i<=n;i++){
			if(l<=r&&i-q[l]+1>aa){
				l++;
			}
			while(l<=r&&b[i][j]<=b[q[r]][j])r--;
			q[++r]=i;
			c[i][j]=b[q[l]][j];
		}
	}
	ll ans=0;
	for(int i=aa;i<=n;i++){
		for(int j=bb;j<=m;j++){
			ans+=c[i][j];
		}
	}
	printf("%lld\n",ans);
	return 0;
}
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值