zoukankan      html  css  js  c++  java
  • 【BZOJ2228】[ZJOI2011] 礼物(巧妙的三部曲)

    点此看题面

    大致题意: 给定一个(n imes m imes k)的木块,其中有一些单位坏了。让你选出一个(a imes a imes b)的木块,求最大的(4ab)

    三部曲

    这道题大概可以分成三步:初始化、求答案、旋转。

    具体放在代码里就是这样子的:

    Init(),Work(),Ro(),Init(),Work(),Ro(),Init(),Work();
    

    其中旋转这一部分是比较简单的,可以直接看代码。而初始化、求答案这两步就让我们一个一个进行分析。

    初始化

    考虑这种三维的东西特别麻烦,肯定要想办法把它给搞成二维的。

    于是我们枚举一维(设为(z))作为(b)的一维,则另两维(设为(x,y))就是(a imes a)这两维。(这也是为什么要旋转的原因)

    我们枚举(z)的每一层,然后对于这一层上每一个格子((i,j)),求出((i,j))为右下角最大的正方形边长

    显然,((i,j))的最大边长最多也只能取到((i-1,j))((i,j-1))最大边长的较小值加(1),然后我们从大到小暴力判断是否能取到每一个值,能取到就直接(break)。这样的总复杂度可以保证是(O(n^3))的。

    至于如何判断,我们把(P)视作(0)(N)视作(1),则一个区域可以被选择,当且仅当区域内权值和等于区域大小(即全是(1)),那么直接二维前缀和搞一下就行了。

    求答案

    好,现在我们已经求出每一个格子作为右下角的最大边长。

    于是,我们就枚举长方体右下角的(x,y)两维坐标((i,j)),然后求此时的答案。

    假设我们在(z)这一维上选取了([l,r])这一区间,那么答案就是(其中(v)表示这个格子的最大边长):

    [(r-l+1) imes min_{p=l}^rv_{i,j,p} ]

    考虑在枚举(i,j)的情况下,(v_{i,j})完全可以看作一个序列(S),即原式相当于:

    [(r-l+1) imes min_{p=l}^rS_p ]

    这个东西应该就非常好搞了吧。。。

    写到这里突然把自己原先A掉的做法Hack掉了,看来这题数据是真的水。。。

    正确的做法是,我们用单调栈维护每一个关键的最小值,从而求出每一个点可以作为哪一段区间的最小值,最后更新答案。

    具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 150
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,m,k,ans;char s[N+5][N+5][N+5];
    namespace BlockPlayer
    {
    	char t[N+5][N+5][N+5];
    	I void Ro()//旋转
    	{
    		RI i,j,p,x=n;for(i=1;i<=n;++i) for(j=1;j<=m;++j) for(p=1;p<=k;++p) t[i][j][p]=s[i][j][p];
    		n=m,m=k,k=x;for(i=1;i<=n;++i) for(j=1;j<=m;++j) for(p=1;p<=k;++p) s[i][j][p]=t[p][i][j];
    	}
    	int c[N+5][N+5],v[N+5][N+5][N+5];
    	I void Init()//初始化
    	{
    		RI i,j,p,w;for(p=1;p<=k;++p) for(i=1;i<=n;++i) for(j=1;j<=m;++j)
    		{
    			c[i][j]=c[i-1][j]+c[i][j-1]-c[i-1][j-1]+(s[i][j][p]=='N'),//二维前缀和
    			w=min(v[i-1][j][p],v[i][j-1][p])+1;W(c[i][j]-c[i-w][j]-c[i][j-w]+c[i-w][j-w]<w*w) --w;//暴算最大边长
    			v[i][j][p]=w;
    		}
    	}
    	int S[N+5],l[N+5],r[N+5];
    	I void Work()//求答案
    	{
    		RI i,j,p,t,T;for(i=1;i<=n;++i) for(j=1;j<=m;++j)//枚举右下角
    		{
    			for(T=0,v[i][j][k+1]=0,p=1;p<=k+1;++p)
    			{
    				l[p]=p;W(T&&v[i][j][S[T]]>=v[i][j][p]) l[p]=l[S[T]],r[S[T--]]=p-1;S[++T]=p;
    				//往单调栈中加一个数,同时维护每个最小值的区间范围
    			}
    			for(p=1;p<=k;++p) Gmax(ans,4*(r[p]-l[p]+1)*v[i][j][p]);//更新答案
    		}
    	}
    }using namespace BlockPlayer;
    int main()
    {
    	RI i,j;for(scanf("%d%d%d",&n,&m,&k),j=1;j<=m;++j) for(i=1;i<=n;++i) scanf("%s",s[i][j]+1);
    	return Init(),Work(),Ro(),Init(),Work(),Ro(),Init(),Work(),printf("%d
    ",ans),0;//三部曲
    }
    
  • 相关阅读:
    MS SQL日期處理
    VS2005快捷键大全
    聯接遠程務器進行操作
    Zune XNA 开发(一,Hello Zune)
    Silverlight for Google Picasa
    Moonlight已经可以下载,目前是0.6版
    Silverlight 2 Beta 2发布
    在Silverlight 2 beta1中使用IronPython等动态语言
    如何在现有通过AttachDbFilename连接的Sql Express数据库上设置membership
    XNA Game Studio 3.0 CTP让Zune不仅仅是媒体播放器
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2228.html
Copyright © 2011-2022 走看看