据说联赛之前写题解可以涨RP

这题的输入格式半天没看懂…其实是有q层摞在一起,每一层大小都是p*r,依次输入q层的情况。那么首先我们枚举三种挖方块的姿势,分别使切出的方块的上面/前面/右面是正方形的面。考虑其中的一种姿势,我们可以O(n^2)枚举正方形的面在原先的大立方体中的右下角坐标(i,j),那么大正方体的每一层中以(i,j)为右下角的完好正方形都有一个最大边长,我们把这些最大边长拿出来形成一个序列。因为最优方案中一定有一个位置的正方形达到了最大边长(否则一定可以得到边长更大的解),所以我们枚举达到最大边长的正方形在哪个位置,找出它最多向两边延伸到哪里,也就是找到两边第一个比它小的最大边长的位置,这一步可以单调栈O(n)枚举所有位置.加起来是O(n^3)

中间还有一步,求以每个位置为右下角的完好正方形最大边长。记某一层以(i,j)为右下角的完好正方形最大边长为f[i][j],那么f[i][j]<=f[i-1][j-1]+1因此我们从f[i-1][j-1]+1开始从大到小枚举f[i][j]的可能取值,只需判断比f[i-1][j-1]多出来的那一部分(第i行和第j列的对应位置)是否全部完好无损即可,找到第一个合法的结果时就跳出循环.每一层的DP看起来都是O(n^3)的,但其实是O(n^2)的。考虑f[1][2],f[2][3],f[3][4],f[4][5]…..,它们所对应的最大完好正方形的上边界是单调下降的,因此对于这一条斜线上的所有状态总的枚举量为O(n).斜线的数目也是O(n)的,因此一层的复杂度是O(n^2),一共n层, DP的总复杂度为O(n^3)

枚举挖方块的姿势的时候,我的写法比较丑,认为是把输入的大立方体旋转到三种不同的姿势,每次都让削出的正方形的面在y轴和z轴确定的平面内(也就是说,分别让大立方体的上面/前面/右面位于yOz平面内)。实现的时候写了三个在不同坐标系下找到对应位置的函数,计算的时候把函数指针传进去,高维数组寻址常数炸天…

#include<cstdio>

#include<algorithm>

using namespace std;

const int maxn=;

char str[maxn][maxn][maxn];

//三种切木块的姿势

char get1(int x,int y,int z){

    return str[x][y][z];

}

char get2(int x,int y,int z){

    return str[y][x][z];

}

char get3(int x,int y,int z){

    return str[y][z][x];

}

int f[maxn][maxn][maxn];//f[i][j][k]:第i层的(j,k)为右下角的最大完好正方形

int sum[maxn][maxn];

void dp(int f[maxn][maxn],int x,int n,int m,char getc(int,int,int)){

    for(int i=;i<=n;++i){

        for(int j=;j<=m;++j){

           // if(getc(x,i,j)=='P')printf("%d %d %d\n",x,i,j);

            sum[i][j]=sum[i-][j]+sum[i][j-]-sum[i-][j-]+(getc(x,i,j)=='P');      

        }//sum[i][j]:在(i,j)左上方有多少坏格子

    }//printf("%d\n",sum[n][m]);

    for(int i=;i<=n;++i){

        for(int j=;j<=m;++j){

            for(int k=f[i-][j-]+;k>=;--k){

                if(sum[i][j]-sum[i-][j]-sum[i][j-k]+sum[i-][j-k]==&&sum[i][j]-sum[i][j-]-sum[i-k][j]+sum[i-k][j-]==){

                    f[i][j]=k;

                    break;

                }

            }

        }

    }

}

int s[maxn],top=;

int rbound[maxn],lbound[maxn];//lbound:某个位置向左数第一个比它小的位置 rbound:某个位置向右数第一个比它小的位置

int work(int maxx,int maxy,int maxz,char getc(int,int,int)){

    for(int i=;i<=maxx;++i){

        dp(f[i],i,maxy,maxz,getc);//把第i层搞出来

    }

    int ans=;

    for(int i=;i<=maxy;++i){

        for(int j=;j<=maxz;++j){

            top=;

            s[]=;

            for(int k=;k<=maxx;++k){

                while(top!=&&f[k][i][j]<=f[s[top]][i][j])--top;

                lbound[k]=s[top];

                s[++top]=k;

            }

            s[]=maxx+;

            top=;

            for(int k=maxx;k>=;--k){

                while(top!=&&f[k][i][j]<=f[s[top]][i][j])--top;

                rbound[k]=s[top];

                s[++top]=k;

            }

            for(int k=;k<=maxx;++k){

                ans=max(ans,*(rbound[k]-lbound[k]-)*f[k][i][j]);

              //  if(4*(rbound[k]-lbound[k]-1)*f[k][i][j]==40)printf("%d %d %d %d %d\n",rbound[k]-lbound[k]-1,f[k][i][j],k,i,j);

            }

        }

    }//printf("%d\n",ans);

    return ans;

}

int main(){

    int p,q,r;scanf("%d%d%d",&q,&p,&r);

    for(int i=;i<=p;++i){//没有读懂题目的坐标描述...瞎读呗,读错了也就相当于把坐标系换了一下

        for(int j=;j<=q;++j){

            scanf("%s",str[i][j]+);

        }//printf("\n");

    }

    int ans=;

    ans=max(ans,work(p,q,r,get1));

    ans=max(ans,work(q,p,r,get2));

    ans=max(ans,work(r,p,q,get3));

    printf("%d\n",ans);

    return ;

}

bzoj2228[ZJOI2011]礼物(gift)的更多相关文章

  1. P3331 [ZJOI2011]礼物(GIFT)

    题解: 首先转化为平面问题 对于每一个z,f(x,y)的值为它能向上延伸的最大高度 ...莫名其妙想出来的是n^4 以每个点作为右下边界n^3枚举再o(n)枚举左下边界计算z的最大值 然而很显然这种做 ...

  2. 【BZOJ2228】[ZJOI2011]礼物(单调栈)

    [BZOJ2228][ZJOI2011]礼物(单调栈) 题面 BZOJ 洛谷 题解 如果这个玩意不是一个三维立方体,而是一个二维的矩形,让你在里面找一个最大正方形,那么全世界都会做. 丢到三维上?似乎 ...

  3. 礼物gift(DP)

    这道题的DP非常的有意思…… 一开始我们总是会以为这是一个背包问题,直接dp[0] = 0,dp[j] += dp[j-c[i]]进行转移.之后统计一下从dp[m-minn]~dp[m]的答案之和为结 ...

  4. BZOJ 2228 礼物(gift)(最大子长方体)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2228 题意:给出一个只含有NP两种字母的长方体.从中找出只含有字母N的长方体,造型为a* ...

  5. [ZJOI2011]礼物

    嘟嘟嘟 正是因为有这样的数据范围,解法才比较暴力. 我们假设取出的长方体常和宽相等,即\(a * a * b\).这样我们每次换两条边相等,搞三次就行. 那么对于第\(k\)层中的第\((i, j)\ ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  7. Java设计模式系列之桥接模式

    桥接模式(Bridge)的定义 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?这就要使用桥接模式 将抽象部分与它的实现部分分离,使它们都可以独立地 ...

  8. [考试反思]1018csp-s模拟测试79:荒谬

    对,如果你想把第5名粘进来,那么图片就是这么夸张. 然而和我并没有什么关系,实在是太菜了. 但是还是想吐槽出题人是真心没良心啊...做了达哥的良心题之后眼光极其挑剔 这套题的部分分设置非常愚蠢,唯一一 ...

  9. js设计模式-代理模式

    1.什么是设计模式? 设计模式:在软件设计过程中常用的代码规范,针对特定的场景 2.应用场景: 麦当劳点餐  观察者模式   规定的代码格式 花店送花  :代理模式 真实对象(男同学)-----代理对 ...

随机推荐

  1. 11-C语言指针&一维数组&字符串

    一.用指针遍历数组元素 1.最普通的遍历方式是用数组下标来遍历元素 1 // 定义一个int类型的数组 2 int a[4] = {1, 2, 3, 4}; 3 4 int i; 5 for (i = ...

  2. 编写Javascript类库(jQuery版) - 进阶者系列 - 学习者系列文章

    这些年主要关注于项目管理方面的工作,编码就比较少了.这几天比较空闲,就想把原来的经验沉淀下来,一个是做好记录,以后如果忘记了还能尽快找回来,第二个是写写博文,算是练练手笔吧. 言归正传,这次写的是Ja ...

  3. jacascript中的原型链以原型

    今地铁上看慕课网js课程,又学习到关于原型的一些知识,记录如下.如有偏差欢迎指正: 三张图要连起来看哦~ 图解: 1.创建一个函数foo. 2.运用函数的prototype属性(这个属性就是实例对象的 ...

  4. yum安装mysql和mysql源,配置mysql

    申明,不要用root安装 1. 下载mysql的repo源 $ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm ...

  5. windows下安装nginx

    说起开发,自己感到非常惭愧,由于公司让我给<绿电侠>项目写整体架构解决方案,才开始接触nginx这个东东,突然觉得它是一把非常好的利器. 本文主要记录在windows下安装nginx,另参 ...

  6. Linux 如何查看修改DNS配置

    DNS服务器介绍 DNS是计算机域名系统(Domain Name System 或Domain Name Service) 的缩写,它是由域名解析器和域名服务器组成的.域名服务器是指保存有该网络中所有 ...

  7. sql server: sql script

    select ProductGUID,ProductName,ProjectGUID from dbo.Product /* F637A079-E22B-4E50-87E9-000147B1B1F4 ...

  8. 设计模式C#实现(十五)——命令模式

    意图 0 适用性 1 结构 2 实现 3 效果 4 参考 5 意图 将请求封装成一个对象,客户接受请求参数:可以对请求排队或者记录请求日志,以及可以支持撤销操作 适用性 抽象出待执行的动作以参数化某对 ...

  9. CentOS配置Nginx+Tomcat7的多站点支持

    注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. #准备工作# 在这之前需要先把Nginx和Tomcat安装好,具体见:<CentOS安装Nginx-1.6.2+安全配置&g ...

  10. 集群(cluster)和高可用性(HA)的概念

    1.1 什么是集群 简单的说,集群(cluster)就是一组计算机,它们作为一个整体向用户提供一组网络资源.这些单个的计算机系统就是集群的节点(node).一个理想的集群是,用户从来不会意识到集群系统 ...