Codeforces 1195E OpenStreetMap(单调队列)
传送:https://codeforces.com/contest/1195/problem/E
题意:给一个$n*m$的矩阵,再给出矩阵数据的构造方法。问所有每个$a*b$的子矩阵的最小值的和是多少。
分析:单调队列先维护列(每一行)的最小值,再对于行(每一列)的最小值进行维护。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=3100; 5 int aa[maxn][maxn],mp[maxn][maxn],q[maxn]; 6 int main(){ 7 int n,m,a,b; scanf("%d%d%d%d",&n,&m,&a,&b); 8 ll g,x,y,z; scanf("%lld%lld%lld%lld",&g,&x,&y,&z); 9 for (int i=1;i<=n;i++){ 10 for (int j=1;j<=m;j++){ 11 aa[i][j]=g; 12 g=(g*x+y)%z; 13 } 14 } 15 for (int i=1;i<=n;i++){ 16 int l=1,r=0; 17 for (int j=1;j<=b;j++){ 18 while (r && aa[i][q[r]]>aa[i][j]) r--; 19 q[++r]=j; 20 } 21 mp[i][1]=aa[i][q[l]]; 22 for (int j=2;j+b-1<=m;j++){ 23 if (q[l]==j-1) l++; 24 while (l<=r && aa[i][q[r]]>aa[i][j+b-1]) r--; 25 q[++r]=j+b-1; 26 mp[i][j]=aa[i][q[l]]; 27 } 28 } 29 ll ans=0; 30 for (int j=1;j<=m;j++){ 31 int l=1,r=0; 32 for (int i=1;i<=a;i++){ 33 while (r && mp[q[r]][j]>mp[i][j]) r--; 34 q[++r]=i; 35 } 36 (ans+=mp[q[l]][j]); 37 for (int i=2;i+a-1<=n;i++){ 38 if (q[l]==i-1) l++; 39 while (l<=r && mp[q[r]][j]>mp[i+a-1][j]) r--; 40 q[++r]=i+a-1; 41 (ans+=mp[q[l]][j]); 42 } 43 } 44 printf("%lld\n",ans); 45 return 0; 46 }