UVA12462 Rectangle

发布时间 2023-08-05 08:29:34作者: JRcxy

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;
}