UVA12462 Rectangle
UVA12462 Rectangle
可以说是广告印刷的加强版。
题目大意
有 \(n\) 个矩形依次相邻,\(m\) 种颜色。第 \(i\) 个矩形高度 \(h_i\),宽度为 \(1\),颜色为 \(c_i\)。求一个面积最大的大矩形,要求大矩形是由这些矩形组成,且大矩形中包含 \(m\) 种颜色。
分析
对与每个 \(h_i\),单调队列找左极限和右极限。
对于要求覆盖的矩形的颜色集合需包含所有颜色,可以开一个 \(color\) 数组。color[i][j]
表示到 \(i\) 为止 \(j\) 颜色个数。最后枚举时,只需要判定对于所有的 \(j\) 是否满足 color[r[i]][j]-color[l[i]-1][j]>0
即可。
AC Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int maxn=100100;
long long color[maxn][35]; // 颜色数组,记录某个位置上方包含某种颜色的方块数目
int q[maxn]; // 存储某个位置的索引
long long l[maxn],r[maxn],h[maxn]; // 存储每个位置的左边界、右边界、高度
int n,m,tail;
int main()
{
while(scanf("%d%d",&n,&m),n||m) // 输入n和m,当n或m不为0时进行循环
{
for(int i=1;i<=n;i++)
scanf("%lld",&h[i]); // 输入每个位置的高度
h[0]=0;h[n+1]=0; // 边界高度设为0,使得最左和最右的边界可以计算
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
color[i][j]=0; // 初始化颜色数组为0
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);x++; // 输入每个位置的颜色,并将颜色值加1(方便后续计算)
for(int j=1;j<=m;j++)
color[i][j]=color[i-1][j]+(j==x); // 根据前一行的颜色数组值,计算当前行的颜色数组值
}
// 预处理计算每个位置的左边界l[i]
tail=0;q[0]=0;
for(int i=1;i<=n;i++)
{
while(h[i]<=h[q[tail]])tail--; // 维护一个单调递增的栈,使得栈内高度递增
l[i]=q[tail]+1; // 左边界l[i]为当前栈顶元素的下一个位置
tail++;q[tail]=i; // 将当前位置入栈
}
// 预处理计算每个位置的右边界r[i]
tail=0;q[0]=n+1;
for(int i=n;i>=1;i--)
{
while(h[i]<=h[q[tail]])tail--; // 维护一个单调递增的栈,使得栈内高度递增
r[i]=q[tail]-1; // 右边界r[i]为当前栈顶元素的上一个位置
tail++;q[tail]=i; // 将当前位置入栈
}
long long ans=0; // 存储最终结果的变量
// 遍历每个位置,计算最大面积
for(int i=1;i<=n;i++)
{
long long s=l[i],t=r[i]; // 获取当前位置的左边界和右边界
bool flag=true;
for(int j=1;j<=m;j++)
if(color[t][j]-color[s-1][j]<=0){flag=false;break;} // 判断该位置上方是否有所有颜色的方块,如果没有,则标记flag为false
if(flag && (t-s+1)*h[i]>ans)ans=(t-s+1)*h[i]; // 如果该位置上方有所有颜色的方块,并且当前面积大于ans,则更新ans为当前面积
}
printf("%lld\n",ans); // 输出最终结果
}
return 0;
}