1. 程式人生 > >[P2219][HAOI2007]修築綠化帶

[P2219][HAOI2007]修築綠化帶

a* include www sizeof scanf tps 不能 i++ span

Link:

P2219 傳送門

Solution:

先對每個點算出以$(i,j)$為矩形右下角時的權值和

問題就轉化為對於以$(i,j)$為右下角的$a*b$的矩形中的最小值

這時模型和 [BZOJ 1047]理想的正方形 就基本相同了,做兩次單調隊列就好了

Tip:

1、$c*d$處於$a*b$邊界的情況不能選,註意邊界判斷

2、算矩陣和時是用$pre[i-a][j-b]$而不是$pre[i-a-1][j-b-1]$……

Code:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=1005;
int n,m,a,b,c,d,x,l,r,q[MAXN],res=0
; int pre[MAXN][MAXN],mx[MAXN][MAXN],mn[MAXN][MAXN],ori[MAXN][MAXN]; int get1(int i,int j,int x) {return pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+x;} int get2(int i,int j,int l,int r) {return pre[i][j]+pre[i-l][j-r]-pre[i][j-r]-pre[i-l][j];} int main() { scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&c,&d);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&x),pre[i][j]=get1(i,j,x); memset(mn,0x3f,sizeof(mn));memset(ori,0x3f,sizeof(ori)); for(int i=a;i<=n;i++) for(int j=b;j<=m;j++) mx[i][j]=get2(i,j,a,b); for(int i=c;i<=n;i++)
for(int j=d;j<=m;j++) ori[i][j]=min(ori[i][j],get2(i,j,c,d)); for(int i=c;i<=n;i++) { l=1;r=0; for(int j=d;j<=m;j++) { while(l<=r&&j-q[l]>b-d-2) l++;//註意去掉邊界情況 while(l<=r&&ori[i][j]<ori[i][q[r]]) r--; q[++r]=j;mn[i][j]=min(mn[i][j],ori[i][q[l]]); } } for(int j=d;j<=m;j++) { l=1;r=0; for(int i=c;i<=n;i++) { while(l<=r&&i-q[l]>a-c-2) l++; while(l<=r&&mn[i][j]<mn[q[r]][j]) r--; q[++r]=i; if(i+1>=a&&j+1>=b&&i+1<=n&&j+1<=m) res=max(res,mx[i+1][j+1]-mn[q[l]][j]); } } printf("%d",res); return 0; }

[P2219][HAOI2007]修築綠化帶