首页 > 其他分享 >P4039 [AHOI2014/JSOI2014] 拼图

P4039 [AHOI2014/JSOI2014] 拼图

时间:2023-07-12 20:33:45浏览次数:35  
标签:lmx le JSOI2014 拼图 P4039 AHOI2014 int 矩形 rmx

Description

JYY 最近迷上了拼图游戏。作为一个计算机科学家,JYY 有一套黑白色的拼图,他希望通过合理的拼接,使得拼出的最终图案中,能包含面积最大的全白色子矩形。JYY 一共有 \(S\) 块拼图,并且由 \(1\) 到 \(S\) 编号。编号为 \(i\) 的拼图是一个 \(N\) 行的方格矩形,每个方格都为黑色或者白色。一开始 JYY 将他的这 \(S\) 块拼图按照编号顺序左右相连依次放在桌上拼成了一个 \(N\) 行 \(M\) 列(这里 \(M=\sum\left(W_i\right)(1 \leq i \leq S)\) 的大矩形。之后 JYY 发现,可以通过改变这\(S\) 块拼图的连接次序,使得拼成的 \(N\) 行 \(M\) 列的大矩形中,最大全白子矩形面积变大。现在 JYY 想知道,怎么拼才能得到最大的全白子矩形呢? 请你帮助他计算出最佳的拼接方案。

\(1\le S,N,W\le 10^5,N\times \sum W_i\le 10^5,T\le 3\)。

Solution

记 \(M=\sum W_i\)。

注意到数据范围中 \(N\times M\le 10^5\),这提示我们可以分两种情况进行。

在讨论之前,先思考一下:如果我们已知矩形的上下边界,如何在 \(\mathcal O(M)\) 的时间里得到答案。

显然,最终答案矩形一定是横跨若干个矩形,然后是左右两端的矩形的一部分(可能没有)。不妨设上下边界分别是 \(l,r\)。那么我们先找出在 \([l,r]\) 全是 \(0\) 的矩形,这些矩形肯定是放中间的。然后再去寻找左右边界。可以记录每个矩形从左或右开始在 \([l,r]\) 中最多有几列,并把其中的最大值所对应的矩形放在左右端点。但是可能某一矩形被同时放在左右端点。为了防止这种情况,需要再统计一个次大值。这个复杂度是 \(\mathcal O(M)\)。

回到上面的讨论。若 \(N\le M\),那么 \(N\le\sqrt{10^5}\),我们就可以直接枚举上下边界,用上文的做法即可,总复杂度 \(\mathcal O(N^2M)\)。反之,那我们统计出每个点上方的第一个 \(1\) 的位置,记为 \(up_{i,j}\),然后以 \([up_{i,j},i]\) 作为左右边界,同样使用上文的做法即可。总复杂度 \(\mathcal O(NM^2)\)。

另外,由于每个矩形的大小不能保证一个较小的范围,所以直接存会爆空间,因此我们要二维转一维存图。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int T,num,n,m,ans,w[N],st[N],ed[N],a[N],sum[N],up[N];
char ch[N];
int id(int x,int y)
{
    if (x<1||y<1) return 0;
    return (y-1)*n+x;
}
int getsum(int xx1,int yy1,int xx2,int yy2) {return sum[id(xx2,yy2)]-sum[id(xx1-1,yy2)]-sum[id(xx2,yy1-1)]+sum[id(xx1-1,yy1-1)];}
void calc(int l,int r)
{
    if (l>r) return;
    for (int i=1,res=0;i<=num;++i)
    {
        for (int j=st[i];j<=ed[i];++j)
        {
            if (getsum(l,j,r,j)==0) ++res;
            else res=0;
            ans=max(ans,res*(r-l+1));
        }
    }
    int lmx[2][2],rmx[2][2],len=0;
    memset(lmx,0,sizeof(lmx));
    memset(rmx,0,sizeof(rmx));
    for (int i=1;i<=num;++i)
    {
        int llen=0,rlen=0;
        for (int j=st[i];j<=ed[i];++j)
            if (getsum(l,j,r,j)==0) llen++;
            else break;
        for (int j=ed[i];j>=st[i];--j)
            if (getsum(l,j,r,j)==0) rlen++;
            else break;
        if (llen==w[i]) len+=w[i];
        else
        {
            if (llen>lmx[0][0]) lmx[1][0]=lmx[0][0],lmx[1][1]=lmx[0][1],lmx[0][0]=llen,lmx[0][1]=i;
            else if (llen>lmx[1][0]) lmx[1][0]=llen,lmx[1][1]=i;
            if (rlen>rmx[0][0]) rmx[1][0]=rmx[0][0],rmx[1][1]=rmx[0][1],rmx[0][0]=rlen,rmx[0][1]=i;
            else if (rlen>rmx[1][0]) rmx[1][0]=rlen,rmx[1][1]=i;
        }
    }
    ans=max(ans,(r-l+1)*len);
    for (int i=0;i<2;++i)
        for (int j=0;j<2;++j)
            if (lmx[i][1]!=rmx[j][1])
                ans=max(ans,(r-l+1)*(len+lmx[i][0]+rmx[i][0]));
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        m=ans=0;
        memset(sum,0,sizeof(sum));
        scanf("%d%d",&num,&n);
        for (int i=1;i<=num;++i)
        {
            scanf("%d",&w[i]);
            st[i]=m+1;
            for (int j=1;j<=n;++j)
            {
                scanf("%s",ch+1);
                for (int k=1;k<=w[i];++k)  
                    a[id(j,m+k)]=ch[k]-'0';
            }
            m+=w[i];
            ed[i]=m;
        }
        for (int i=1;i<=n;++i)
            for (int j=1;j<=m;++j)
                sum[id(i,j)]=sum[id(i,j-1)]+sum[id(i-1,j)]-sum[id(i-1,j-1)]+a[id(i,j)];
        for (int j=1;j<=m;++j)
            for (int i=1;i<=n;++i)
            {
                if (a[id(i,j)]==1) up[id(i,j)]=i;
                else up[id(i,j)]=up[id(i-1,j)];
            }
        if (n<=m)
        {
            for (int i=1;i<=n;++i)
                for (int j=i;j<=n;++j)
                    calc(i,j);
        }
        else
        {
            for (int i=1;i<=n;++i)
                for (int j=1;j<=m;++j)
                    calc(up[id(i,j)]+1,i);
        }
        printf("%d\n",ans);
    }
    return 0;
}

标签:lmx,le,JSOI2014,拼图,P4039,AHOI2014,int,矩形,rmx
From: https://www.cnblogs.com/Livingston/p/17548760.html

相关文章

  • [AHOI2014/JSOI2014] 骑士游戏
    [AHOI2014/JSOI2014]骑士游戏观察性质:对于一类怪兽,要么全部使用普通攻击,要么全部使用魔法攻击。若对怪兽\(i\)满足\(s_i>k_i\),则必使用魔法攻击。若按照怪兽的生成关系连有向边建图,则一个环内\(k\)值最小的怪兽必使用魔法攻击。注意到,如果我们已经确定了完全消灭一......
  • [JZOJ3864]【JSOI2014】歌剧表演
    DescriptionSolution这题非常有意思。本来我想各种二进制搞一波,但我看到数据后我放弃了。。。其实这题十分的水。我们把目前分辨不出的放在同一集合。那么对于演出操作,就......
  • [AHOI2014/JSOI2014]骑士游戏
    链接:https://www.luogu.com.cn/problem/P4042题目描述:对于一个怪物\(i\),可以花费\(c_{i}\)的代价将其变为一个怪物集合,或花费\(c2_{i}\)的代价消灭他。求消灭怪物\(1\)的......
  • [AHOI2014/JSOI2014]支线剧情
    链接:https://www.luogu.com.cn/problem/P4044题目描述:给定一个\(DAG\),求若干条条路径,覆盖所有的点,并最小化路径的权值和。题解:由于图是一个\(DAG\),所以原问题可以转化......
  • [AHOI2014/JSOI2014]奇怪的计算器
    链接:https://www.luogu.com.cn/problem/P4041题目描述:给定一个数列\(a\),与常数\(L\),\(R\),实现下列四个操作:1.将所有数加\(d\)。2.将所有数减\(d\)。3.将所有数乘\(d......
  • [JSOI2014]支线剧情2
    链接:https://vjudge.net/problem/HYSBZ-5031题目描述:给定一个树形图,规定一号点为根节点。到达一个点时可以进行下列操作:\(1\).沿着一条有向边走到下一个节点。\(2\).回......
  • [AHOI2014/JSOI2014]拼图
    链接:https://www.luogu.com.cn/problem/P4039题目描述:有一些长为\(n\),宽为\(w_{i}\)的黑白色矩形,要将它们拼成一个\(n\timesm\)的大矩形,求大矩形中最大的全白子矩形的面......
  • [AHOI2014/JSOI2014]支线剧情
    链接:https://www.luogu.com.cn/problem/P4044题目描述:给定一个$DAG$,求若干条条路径,覆盖所有的点,并最小化路径的权值和。题解:由于图是一个$DAG$,所以原问题可以转化为,......
  • [AHOI2014/JSOI2014]奇怪的计算器
    链接:https://www.luogu.com.cn/problem/P4041题目描述:给定一个数列$a$,与常数$L$,$R$,实现下列四个操作:1.将所有数加$d$。2.将所有数减$d$。3.将所有数乘$d$。4.......
  • [AHOI2014/JSOI2014]拼图
    链接:https://www.luogu.com.cn/problem/P4039题目描述:有一些长为$n$,宽为$w_{i}$的黑白色矩形,要将它们拼成一个$n\timesm$的大矩形,求大矩形中最大的全白子矩形的面积的......