A Rectangular Barn
Ever the capitalist, Farmer John wants to extend his milking business by purchasing more cows. He needs space to build a new barn for the cows.
FJ purchased a rectangular field with R (1 ≤ R ≤ 3,000) rows numbered 1..R and C (1 ≤ C ≤ 3,000) columns numbered 1..C. Unfortunately, he realized too late that some 1x1 areas in the field are damaged, so he cannot build the barn on the entire RxC field.
FJ has counted P (0 ≤ P ≤ 30,000) damaged 1x1 pieces and has asked for your help to find the biggest rectangular barn (i.e., the largest area) that he can build on his land without building on the damaged pieces.
PROGRAM NAME: rectbarn
INPUT FORMAT
- Line 1: Three space-separated integers: R, C, and P.
- Lines 2..P+1: Each line contains two space-separated integers, r and c, that give the row and column numbers of a damaged area of the field
SAMPLE INPUT (file rectbarn.in)
3 4 2 1 3 2 1
OUTPUT FORMAT
- Line 1: The largest possible area of the new barn
SAMPLE OUTPUT (file rectbarn.out)
6
OUTPUT DETAILS
1 2 3 4 +-+-+-+-+ 1| | |X| | +-+-+-+-+ 2|X|#|#|#| +-+-+-+-+ 3| |#|#|#| +-+-+-+-+
Pieces marked with 'X' are damaged and pieces marked with '#' are part of the new barn.
————————————————————————题解
又见DP……
感受到智商深深的不足
翻译标准题解……
First, note that the largest possible barn will be touching a rock (i.e., a damaged area) or a side of the field on all four of its sides, as otherwise we could make a larger barn by extending the supposed largest barn on a side which isn't blocked. Consider any rock on the top side. We can view the barn as extending out to the left and to the right from the column of this rock.
首先,注意到最大可能的谷棚会碰到一个岩石(也就是一个损坏区域)或者它四周田地的边界,故而我们可以制造更大的牛棚通过在没有撞上的地方扩展已经确定的最大牛棚。考虑把一个岩石放在顶端,在岩石所在的这一列向左和右扩展。
We loop through the rows, and then through the columns. For the i-th row and the j-th column, we consider the largest barn starting at the most recent rock (or the top side of the field) in the j-th column, and extending down to the i-th row. We have explicitly defined the top and bottom sides of the barn, so we simply want to extend the left and right sides as far out as possible from the j-th column. If we already have the maximum distance from the j-th column that the left and right sides can extend if the bottom side of the barn is the (i-1)-st row, then for each of the left and the right sides, we just take the minimum of the old value and the distance to the nearest rock on the i-th row to calculate the new value for the maximum extensions to the left and the right of our barn. (If we had just hit a rock on the (i-1)-st row, we assume that we could reach all the way to the side of the field.)
我们循环行,然后循环列,在i行j列我们考虑最大的牛棚开始在最近的岩石(或者田地的顶端)在j列,然后扩展到i行。现已明确牛棚上下边界,故而从j列左右拓展,【我就不矫饰语句了】预处理的方法是向左(右)最大延伸距离是对于i-1行的向左(右)延伸最大距离和i行向左(右)延伸最大距离取个max
In this way, we scan down row by row. As each maximal barn is bounded on the top side by some rock or by the top side of the field, we will find it when we're scanning through the row corresponding to the bottom side of the barn.
因为我们一行行扫描【所以我们可以滚动数组,USACO空间只有16M。】因此每个最大的牛棚顶边会限制在一些岩石和田地顶端,我们会找到它当我们扫描这个最大牛棚的底端。
我这里的l[x]记录向左延伸最远到哪个点,r[x]向右延伸最远到哪个点,和题解所叙述不太一样
1 /* 2 ID: ivorysi 3 LANG: C++ 4 PROG: rectbarn 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <queue> 10 #include <set> 11 #include <vector> 12 #include <algorithm> 13 #define siji(i,x,y) for(int i=(x);i<=(y);++i) 14 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j) 15 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i) 16 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j) 17 #define inf 0x5f5f5f5f 18 #define ivorysi 19 #define mo 97797977 20 #define hash 974711 21 #define base 47 22 #define fi first 23 #define se second 24 #define pii pair<int,int> 25 #define esp 1e-8 26 typedef long long ll; 27 using namespace std; 28 bool damage[3005][3005]; 29 int h[3005],l[3005],r[3005],tl[3005],tr[3005]; 30 int n,m,p,x,y,ans; 31 void solve() { 32 scanf("%d%d%d",&n,&m,&p); 33 siji(i,1,p) { 34 scanf("%d%d",&x,&y); 35 damage[x][y]=1; 36 } 37 siji(i,1,m) {r[i]=m+1;l[i]=1;} 38 siji(i,1,n) { 39 tl[0]=0;tl[m+1]=m+1; 40 siji(j,1,m) { 41 if(damage[i][j]) tl[j]=j; 42 else tl[j]=tl[j-1]; 43 } 44 tr[0]=0;tr[m+1]=m+1; 45 gongzi(j,m,1) { 46 if(damage[i][j]) tr[j]=j; 47 else tr[j]=tr[j+1]; 48 } 49 siji(j,1,m) { 50 if(damage[i][j]) { 51 h[j]=0; 52 l[j]=0; 53 r[j]=m+1; 54 } 55 else { 56 h[j]=h[j]+1; 57 l[j]=max(l[j],tl[j]+1); 58 r[j]=min(r[j],tr[j]-1); 59 ans=max(ans,(r[j]-l[j]+1)*h[j]); 60 } 61 } 62 } 63 printf("%d ",ans); 64 } 65 int main(int argc, char const *argv[]) 66 { 67 #ifdef ivorysi 68 freopen("rectbarn.in","r",stdin); 69 freopen("rectbarn.out","w",stdout); 70 #else 71 freopen("f1.in","r",stdin); 72 #endif 73 solve(); 74 return 0; 75 }