• BZOJ 3873: [Ahoi2014]拼图


    BZOJ 3873: [Ahoi2014]拼图

    标签(空格分隔): OI-BZOJ OI-DP


    Time Limit: 10 Sec
    Memory Limit: 256 MB


    Description

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

    Input

    每个输入文件中包含多组测试数据。输入文件第一行包含一个整数T,代表

    测试数据的组数,接下来按顺序描述了每组测试数据。
    每组测试数据的第一行包含两个整数S和N。
    接下来S组输入,第i组对应编号为i的拼图。
    在第i组输入中,第一行包含一个整数;
    接下来N行描述一个N行列的0/1矩形;
    其中第x行y列为0则表示该拼图对应位置的颜色是白色,反之则为黑色。
    Output

    对于每组数据输出一行包含一个整数ans,表示最大可能的全白色子矩形的面积。

    Sample Input

    1

    34

    4

    1001

    0000

    0010

    1001

    3

    000

    010

    000

    011

    2

    00

    10

    01

    00
    Sample Output

    6
    HINT

    对于100%的数据满足1<=S,N,Wi<=105,N*Sigma(Wi)<=105,T<=3

    添加数组一组--2015.02.28


    Solution####

    (m=sumlimits_{i=1}^S{w_i})
    算法1:枚举矩形上下边界,每个块作为左端块,右端块,中间块分别考虑。
    对于在某个块内部的矩形求一下最大连续0的个数即可,复杂度(O(n*n*m))
    算法2:求出每个点往上延伸的最大长度,枚举每个点作为矩形的下边界上的点,向上延伸的极限作为矩形的下边界,可以(O(m))求出答案。对于这个算法的正确性可以朴素的理解:对于相同左右边界的矩形肯定尽量向上延伸,上边界会被某个东西挡住。这个方案在枚举到,被挡住位置的正下方所对应下边界上的位置的时候,会被包含入答案。复杂度(O(n*m*m))
    (n<sqrt{n*m})时使用算法1,否则使用算法2


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<bitset>
    #include<vector>
    using namespace std;
    #define LL long long
    int read()
    {
        int s=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
        return s*f;
    }
    int read2()
    {
        int s=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';break;ch=getchar();}
        return s*f;
    }
    //smile please
    int T,S,N,w[100005],ans;
    bitset<100005> sa[405],pa;
    int rr[405];
    int main()
    {
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        for(T=read();T--;)
           {S=read();N=read();ans=0;
            if(N<=300)
               {
                for(int i=1;i<=S;i++)
                   {w[i]=read()+w[i-1];
                    for(int j=1;j<=N;j++)
                        for(int k=w[i-1]+1;k<=w[i];k++)
                            sa[j][k]=read2();
                   }
                for(int i=1;i<=N;i++)
                   {pa=sa[i];
                    for(int j=i;j<=N;j++)
                       {pa|=sa[j];
                        int sum=0,sum2=0;
                        int l1=0,lw1=0,l2=0;
                        int r1=0,rw1=0,r2=0;
                        for(int k=1;k<=w[S];k++)
                            sum=(pa[k]?0:sum+1),
                            ans=max(ans,(j-i+1)*sum);
                        for(int k=1;k<=S;k++)
                           {sum=0;
                            for(int l=w[k-1]+1;l<=w[k]&&!pa[l];l++)
                                sum++;
                            if(sum==w[k]-w[k-1])
                              {sum2+=w[k]-w[k-1];continue;}
                            if(sum>l1)
                              l2=l1,l1=sum,lw1=k;
                            else
                              if(sum>l2)
                                l2=sum;
                            sum=0;
                            for(int l=w[k];l>=w[k-1]+1&&!pa[l];l--)
                                sum++;
                            if(sum>r1)
                              r2=r1,r1=sum,rw1=k;
                            else
                              if(sum>r2)
                                r2=sum;
                           }
                        ans=max(ans,((lw1==rw1?max(l1+r2,l2+r1):l1+r1)+sum2)*(j-i+1));
                       }
                   }
               }
            else
               {
                for(int i=1;i<=S;i++)
                   {w[i]=read()+w[i-1];
                    for(int j=1;j<=N;j++)
                        for(int k=w[i-1]+1;k<=w[i];k++)
                            sa[k][j]=read2();
                   }
                for(int j=1;j<=w[S];j++)
                    rr[j]=0;
                for(int i=N;i>=1;i--)
                   {for(int j=1;j<=w[S];j++)
                        rr[j]=(sa[j][i]?0:rr[j]+1);
                    for(int j=1;j<=w[S];j++)
                       {int sum=0,sum2=0;
                        int l1=0,lw1=0,l2=0;
                        int r1=0,rw1=0,r2=0;
                        for(int k=1;k<=w[S];k++)
                            sum=(rr[k]<rr[j]?0:sum+1),
                            ans=max(ans,rr[j]*sum);
                        for(int k=1;k<=S;k++)
                           {sum=0;
                            for(int l=w[k-1]+1;l<=w[k]&&rr[l]>=rr[j];l++)
                                sum++;
                            if(sum==w[k]-w[k-1])
                              {sum2+=w[k]-w[k-1];continue;}
                            if(sum>l1)
                              l2=l1,l1=sum,lw1=k;
                            else
                              if(sum>l2)
                                l2=sum;
                            sum=0;
                            for(int l=w[k];l>=w[k-1]+1&&rr[l]>=rr[j];l--)
                                sum++;
                            if(sum>r1)
                              r2=r1,r1=sum,rw1=k;
                            else
                              if(sum>r2)
                                r2=sum;
                           }
                        ans=max(ans,((lw1==rw1?max(l1+r2,l2+r1):l1+r1)+sum2)*rr[j]);
                       }
                   }
               }
            printf("%d
    ",ans);
           }
        //fclose(stdin);
        //fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    Linux 多线程环境下 进程线程终止函数小结
    C++:vector中的resize()函数 VS reserve()函数
    Linux进程间通信之信号量(semaphore)、消息队列(Message Queue)和共享内存(Share Memory)
    Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
    求全与求专
    wpf \silverlight 保存控件为图片
    软件版本号详解(转)
    WPF 自定义快捷键命令(Command)(转)
    WIN2003系统远程桌面多连接数设置终极大法
    程序集强命名与GAC
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5245766.html
Copyright © 2020-2023  润新知