P2219 [HAOI2007]修筑绿化带
这道题跟理想的正方形很像,不大明白蛤OI是怎么想的,一年出两道这么相近的题
这道题有两个矩形,所以就有了两种做法(说是两种做法,其实只是维护的矩形不同)
一种是维护大矩形,一种是维护小矩形,我这里采取了维护小矩形的方法
先求出以\((i,j)\)为左上角的大矩形和小矩形的权值和为多少,然后用单调队列维护以(i,j)为左上角的大矩形里能放得最小的小矩形是哪个,最后做差得答案即可
下面是代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 1005
using namespace std;
inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}int n,m,a,b,c,d,ans,w[maxn][maxn];
int w1[maxn][maxn],w2[maxn][maxn],x[maxn][maxn],y[maxn][maxn];
struct ahaha{
int s,id;
}q[maxn];int h,t;
int main(){
n=read();m=read();a=read();b=read();c=read();d=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
w[i][j]=w[i-1][j]+w[i][j-1]+read()-w[i-1][j-1];
for(int i=1;i<=n-c+1;++i)
for(int j=1;j<=m-d+1;++j){
w1[i][j]=w[i+c-1][j+d-1]-w[i+c-1][j-1]-w[i-1][j+d-1]+w[i-1][j-1];
if(i<=n-a+1&&j<=m-b+1)
w2[i][j]=w[i+a-1][j+b-1]-w[i+a-1][j-1]-w[i-1][j+b-1]+w[i-1][j-1];
}
for(int i=1;i<=n-c+1;++i){
int l=b-d+1;
for(int j=1;j<l;++j){
while(h<=t&&w1[i][j]<=q[t].s)--t;
q[++t]={w1[i][j],j};
}
for(int j=l;j<=m-d+1;++j){
while(h<=t&&j-q[h].id>=l-1)++h;
x[i][j-l+1]=q[h].s;
while(h<=t&&w1[i][j]<=q[t].s)--t;
q[++t]={w1[i][j],j};
}
h=1,t=0;
}
for(int i=1;i<=m-b+1;++i){
int l=a-c+1;
for(int j=1;j<l;++j){
while(h<=t&&x[j][i]<=q[t].s)--t;
q[++t]={x[j][i],j};
}
for(int j=l;j<=n-c+1;++j){
while(h<=t&&j-q[h].id>=l-1)++h;
y[j-l+1][i]=q[h].s;
while(h<=t&&x[j][i]<=q[t].s)--t;
q[++t]={x[j][i],j};
}
h=1,t=0;
}
for(int i=1;i<=n-a+1;++i)
for(int j=1;j<=m-b+1;++j)
ans=max(ans,w2[i][j]-y[i][j]);
printf("%d\n",ans);
return 0;
}
所有文字著作权归本人所有,禁止转载抄袭,若盗版进行商业运营,本人必将追究到底。