题意:给一个矩阵求a*b的子矩阵里最小值之和
思路是开n个单调队列,然后当j>=b时,n个单调队列就会维护每一行每个长度为b的区间里的最小值,然后我们要从这n个单调队列的队头里,每a个取一个最小值(此最小值即为对应的a*b矩阵里的最小值),所以可以再用单调队列优化为O(N),不然直接暴力N*A会t。
#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;
typedef pair<int,int> pii;
const int maxn=3e3+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
int q[maxn][maxn],h[maxn],t[maxn];
pii qq[maxn];
ll g[(int)1e7],mod,x,y,mp[maxn][maxn];
int main()
{
int n,m,a,b;
ll ans=0;
scanf("%d%d%d%d%I64d%I64d%I64d%I64d",&n,&m,&a,&b,&(g[0]),&x,&y,&mod);
for(int i=1;i<=n;i++) h[i]=1,t[i]=0;
for(int i=1;i<=1e7-5;i++)
g[i]=(g[i-1]*x+y)%mod;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mp[i][j]=g[(i-1)*m+j-1];
for(int j=1;j<=m;j++)
{
for(int i=1;i<=n;i++)
{
while(h[i]<=t[i]&&mp[i][q[i][t[i]]]>=mp[i][j]) t[i]--;
q[i][++t[i]]=j;
while(j-q[i][h[i]]>=b) h[i]++;
}
//cout<<endl;
//for(int i=1;i<=n;i++) cout<<mp[i][q[i][h[i]]<<" ";
//cout<<endl;
if(j>=b)
{
int head=1,tail=0;
for (int i = 1; i <=n;i++)
{
while(head<=tail&&mp[qq[tail].first][qq[tail].second]>=mp[i][q[i][h[i]]]) tail--;
qq[++tail]=make_pair(i,q[i][h[i]]);
while(i-qq[head].first>=a) head++;
if(i>=a)
ans+=mp[qq[head].first][qq[head].second];
}
}
}
printf("%I64d
",ans);
return 0;
}
模板
#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;
}