Recovering Gold Slabs from Visible Cells
National Olympiad — National round (2012 season)
Submission name: goldbox.cpp
Problem summary
The top-view matrix labels the uppermost gold slab over each cell. Every rectangular slab has at least one visible cell on each of its four sides. Recover total weight, including hidden slab area.
Input
L W N G followed by W rows of L labels 0…N. G is grams per square centimetre.
Output
The total gold weight.
Constraints
1 ≤ L ≤ 124; 1 ≤ W ≤ 86; 1 ≤ N ≤ 50; 17 ≤ G ≤ 10^10; all four sides of each slab have visible cells.
Worked example
Input and output for the worked example discussed below.
Input
5 4 3 250 0 2 2 2 0 0 2 3 3 3 1 1 3 3 3 1 1 2 2 0
Output
5500
Solution analysis
- For each nonzero label record minimum and maximum visible row and column. Counting only visible cells would underestimate metal covered by higher slabs.
- The four-visible-sides guarantee makes those extrema the slab’s actual boundaries. Its full area is (maxRow−minRow+1)(maxColumn−minColumn+1). Add overlapping slab areas because stacked layers all contain gold.
- The sample slabs have areas 4,12,6. Total area 22 times G=250 gives 5500 grams. Use 64-bit arithmetic because the area-weight product can exceed int.
Why it works
Visible cells lie inside their slab, so their extrema cannot extend past its boundaries. Visibility on every side ensures each true boundary is reached. Each recovered bounding rectangle is therefore exact, and summing their areas counts every layer before multiplication by G.
Watch out. Compute total slab area, not union area or visible area. Cell boundaries are inclusive. The PDF’s G bound is 10^10, verified from its superscript typography.
Commented C++17 solution
An independently written complete program with standard headers.
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int main(){
int length;
int width;
int count;
long long weight;
cin>>length>>width>>count>>weight;
vector<int>minRow(count+1,width);
vector<int>maxRow(count+1,-1);
vector<int>minColumn(count+1,length);
vector<int>maxColumn(count+1,-1);
for(int r=0;r<width;r++){
for(int c=0;c<length;c++){
int label;
cin>>label;
if(label>0){
minRow[label]=min(minRow[label],r);
maxRow[label]=max(maxRow[label],r);
minColumn[label]=min(minColumn[label],c);
maxColumn[label]=max(maxColumn[label],c);
}
}
}
long long area=0;
for(int label=1;label<=count;label++){
// Visible cells attain all four true slab boundaries.
area+=1LL*(maxRow[label]-minRow[label]+1)*(maxColumn[label]-minColumn[label]+1);
}
cout<<area*weight<<'\n';
}