P2219 [HAOI2007]修筑绿化带(二维单调队列)
作者:互联网
题目描述
为了增添公园的景致,现在需要在公园中修筑一个花坛,同时在画坛四周修建一片绿化带,让花坛被绿化带围起来。
如果把公园看成一个M*N的矩形,那么花坛可以看成一个C*D的矩形,绿化带和花坛一起可以看成一个A*B的矩形。
如果将花园中的每一块土地的“肥沃度”定义为该块土地上每一个小块肥沃度之和,那么,
绿化带的肥沃度=A*B块的肥沃度-C*D块的肥沃度
为了使得绿化带的生长得旺盛,我们希望绿化带的肥沃度最大。
输入输出格式
输入格式:
第一行有6个正整数M,N,A,B,C,D
接下来一个M*N的数字矩阵,其中矩阵的第i行j列元素为一个整数Xij,表示该花园的第i行第j列的土地“肥沃度”。
输出格式:
一个正整数,表示绿化带的最大肥沃程度。
输入输出样例
输入样例#1: 复制
4 5 4 4 2 2 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
输出样例#1: 复制
132
说明
数据范围
30%的数据,1<=M,N<=50
100%的数据,1<=M,N<=1000,1<=A<=M,1<=B<=N,1<=C<=A-2,1<=D<=B-2,1<=“肥沃度”<=100
首先n**4暴力 枚举大矩形,在枚举里面可能存在的小矩形
优化: 发现枚举里面小矩形的步骤可以省略,因为我们每次枚举小矩形都是相对大矩形在一定范围内的,所以可以预处理出一定范围内的小矩形的最小值,这样的话直接枚举打矩形然后减去一定范围内的小矩形的最小值就行了,复杂度o(n**2)
预处理出所有小矩形的面积
此题是二维的,所以先处理的在行方向上固定列范围内的最小值,在此基础上处理行方向上一定范围的最小值
1 #include"bits/stdc++.h" 2 using namespace std; 3 4 int f[1005][1005]; 5 int sum[1005][1005]; 6 7 int f1[1005][1005]; 8 int f2[1005][1005]; 9 int f3[1005][1005]; 10 11 int n,m,a,b,c,d; 12 13 int work(int x1,int y1,int x2,int y2) 14 { 15 return sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]; 16 } 17 18 int main() 19 { 20 cin>>n>>m>>a>>b>>c>>d; 21 for (int i=1;i<=n;i++) 22 { 23 for (int j=1;j<=m;j++) 24 { 25 scanf("%d",&f[i][j]); 26 } 27 } 28 29 for (int i=1;i<=n;i++) 30 { 31 for (int j=1;j<=m;j++)sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+f[i][j]; 32 } 33 34 /* for (int i=1;i<=n;i++) 35 { 36 for (int j=1;j<=m;j++)cout<<sum[i][j]<<" ";cout<<endl; 37 }*/ 38 39 for (int i=c+1;i<n;i++) 40 { 41 for (int j=1+d;j<=1+m;j++) f1[i][j]=sum[i][j]-sum[i-c][j]-sum[i][j-d]+sum[i-c][j-d]; 42 } 43 44 deque<int> q; 45 46 for (int i=c+1;i<n;i++)//这从c+1开始,是防止从花坛边上转移过来,下同。 47 { 48 while (!q.empty())q.pop_front(); 49 for (int j=d+1;j<m;j++) 50 { 51 while (!q.empty()&&q.front()+b-d-2+1-1<j)q.pop_front(); 52 while (!q.empty()&&f1[i][q.back()]>f1[i][j])q.pop_back(); 53 q.push_back(j);f2[i][j]=f1[i][q.front()]; 54 // cout<<i<<": "<<q.size()<<endl; 55 } 56 } 57 58 59 for (int j=d+1;j<m;j++) 60 { 61 while (!q.empty())q.pop_front(); 62 for (int i=c+1;i<n;i++) 63 { 64 while (!q.empty()&&q.front()+a-c-2+1-1<i)q.pop_front(); 65 while (!q.empty()&&f2[q.back()][j]>f2[i][j])q.pop_back(); 66 q.push_back(i);f3[i][j]=f2[q.front()][j]; 67 //cout<<j<<": "<<q.size()<<endl; 68 } 69 } 70 71 72 73 74 /* for (int i=c;i<=n;i++) 75 { 76 77 for (int j=d;j<=m;j++) 78 { 79 cout<<f3[i][j]<<" "; 80 } 81 cout<<endl; 82 }*/ 83 84 int ans=0; 85 for (int i=a;i<=n;i++) 86 { 87 for (int j=b;j<=m;j++) 88 { 89 ans=max(ans,work(i-a+1,j-b+1,i,j)-f3[i-1][j-1]); 90 } 91 } 92 93 94 return cout<<ans,0; 95 96 97 }
标签:矩形,绿化带,int,sum,肥沃,HAOI2007,1005,P2219 来源: https://www.cnblogs.com/zhangbuang/p/10365746.html