据说联赛之前写题解可以涨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. [翻译]——SQL Server使用链接服务器的5个性能杀手

    前言: 本文是对博客http://www.dbnewsfeed.com/2012/09/08/5-performance-killers-when-working-with-linked-server ...

  2. Java 堆

    特性: 虚拟机启动时创建的线程共享的内存区域,所有实例对象和数组对象分配内存的区域 GC垃圾手机管理器管理的主要区域,GC堆 容量可以固定,也可以动态扩展,自动收缩 -Xmx最大堆大小 -Xms最小. ...

  3. mysql 队列 实现并发读

    原文地址:http://www.jb51.net/article/30164.htm 队列是常用的数据结构,基本特点就是先入先出,在事务处理等方面都要用到它,有的时候是带有优先级的队列.当队列存在并发 ...

  4. charles 抓取eclipse中的请求

    charles抓取eclipse中的请求 有时候,想要监测eclipse中发送get获取post请求,一样可以使用代理方式: 1.eclipse代码设置 代码中添加,可以就写在主函数中,然后再调用请求 ...

  5. Centos 安装jdk1.8

    我是根据右边链接进行安装的 ,但是第一步不同噢.http://www.cnblogs.com/spiders/archive/2016/09/06/5845727.html 1.下载rpm安装文件. ...

  6. 算法: 斐波那契数列C/C++实现

    斐波那契数列: 1,1,2,3,5,8,13,21,34,....     //求斐波那契数列第n项的值 //1,1,2,3,5,8,13,21,34... //1.递归: //缺点:当n过大时,递归 ...

  7. 【推荐】CentOS安装Tomcat-7.0.57+启动配置+安全配置+性能配置

    注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. #准备工作# 在安装Tomcat之前,请确保已经安装了JDK-1.7环境,具体见<CentOS安装JDK-1.7>. ...

  8. java自带工具-jps、jinfo、jstack、jstat、jmap

    掌握java自带的这些监控工具,有助与我们很好的分析问题和jvm性能调优秀.收集了些网上整理很好的文章. Java监控工具.调优.调试辅助函数 Java自带的GUI性能监控工具Jconsole以及Ji ...

  9. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  10. 你不一定懂的cpu显示信息

    在linux命令中用top查看系统的情况,在cpu这一行有一些分部表示什么 下面有一篇博文,对此写的非常清楚,特转载.猛击下面的链接 http://www.cnblogs.com/yjf512/p/3 ...