Codeforces Round #574 (Div. 2) E. OpenStreetMap(单调队列)

题目链接
在这里插入图片描述
思路:要想知道ab这个子矩阵最小的元素,我们可以维护两个单调队列,首先我们维护n行的单调队列q,每行单调队列存的就是每b个区间的最小值,当遍历到b列以后,我们再维护一个单调队列p,它维护的是这n行的q队列的队头元素每a个区间的最小值,如此ab子矩阵的最小就得出来了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e3+10;
int q[maxn][maxn],n,m,a,b;
pair<int,int>p[maxn];
ll g[maxn*maxn],x,y,z,s[maxn],e[maxn],h[maxn][maxn],ans;
int main()
{
	scanf("%d%d%d%d",&n,&m,&a,&b);
	scanf("%lld%lld%lld%lld",&g[0],&x,&y,&z);
	for(int i=1;i<=n*m;++i)
	g[i]=(g[i-1]*x+y)%z;
	for(int i=1;i<=n;++i)
	for(int j=1;j<=m;++j)
	h[i][j]=g[(i-1)*m+j-1];
	for(int i=1;i<=n;++i) s[i]=1,e[i]=0;
	for(int j=1;j<=m;++j)
	{
		for(int i=1;i<=n;++i)
		{
			while(s[i]<=e[i]&&h[i][q[i][e[i]]]>=h[i][j]) e[i]--;
			q[i][++e[i]]=j;
			while(j-q[i][s[i]]>=b) s[i]++;
		}
		if(j>=b)
		{
			int head=1,tail=0;
			for(int i=1;i<=n;++i)
			{
				while(head<=tail&&h[p[tail].first][p[tail].second]>=h[i][q[i][s[i]]])  tail--;
				p[++tail]={i,q[i][s[i]]};
				while(i-p[head].first>=a) head++;
				if(i>=a) ans+=h[p[head].first][p[head].second];
			}
		}
	}
	printf("%lld\n",ans);
 } 

这里再贴一个大佬的单调队列模板,很好用。。。

#include<bits/stdc++.h>//单调队列又称为滑动窗口
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
const int maxn=1e6+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
int a[maxn],q[maxn],ans1[maxn],ans2[maxn];
 
 
 
int main()
{
    int n,m,h,t;
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&(a[i]));
    h=1,t=0;
    for(int i=1;i<=n;i++)//求m区间内最小值 以i为末尾的m区间  维护增队列
    {
        while(h<=t&&a[q[t]]>=a[i]) t--;//删去队尾的无用元素
        q[++t]=i;
        while(i-q[h]+1>=m+1) h++;//队头删去在所需区间外的元素
        if(i>=m)
            ans1[i-m+1]=a[q[h]];
    }
    h=1,t=0;
    for(int i=1;i<=n;i++)//求m区间内最大值   以i为末尾的m区间
    {
        while(h<=t&&a[q[t]]<=a[i]) t--;//删去队尾的无用元素
        q[++t]=i;
        while(i-q[h]+1>=m+1) h++;//队头删去在所需区间外的元素
        if(i>=m)
            ans2[i-m+1]=a[q[h]];
    }
    for(int i=1;i+m-1<=n;i++) printf("%d ",ans1[i]);
    cout<<endl;
    for(int i=1;i+m-1<=n;i++) printf("%d ",ans2[i]);
    cout<<endl;
    return 0;
}
 
 
 

发布了144 篇原创文章 · 获赞 0 · 访问量 4927

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104545678