2017.10.12 礼物(zjoi2011) 失败总结

本文探讨了一个三维矩阵问题,通过对比两种不同的算法实现:一种是基于暴力搜索的方法,但容易超时;另一种是采用单调栈优化,能够显著提高效率并获得正确的结果。文章详细介绍了两种方法的实现过程及代码细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

听说n^4能过,于是愉快地敲了n^4  ,还带了两个最优性剪枝。。

结果事实证明是别人家的n^4.。。(wys?


很奇怪玄学剪枝有时2^50次方都能过,为什么这个连1e10都过不了。.。


TLE代码:

#include<iostream>
#include<cstdio>
using namespace std;
int x,y,z,xx[155][155][155],yy[155][155][155],zz[155][155][155],i,j,k,lin[155],a,qi,tu[155][155][155],ans;
char ch;
int main()
{
	scanf("%d%d%d",&y,&x,&z);
	for(i=1;i<=x;i++)
	for(j=1;j<=y;j++)
	for(k=1;k<=z;k++)
	{
		scanf("%c",&ch);
		while(ch!='N'&&ch!='P')scanf("%c",&ch);
		if(ch=='N')tu[i][j][k]=1;
		else tu[i][j][k]=0;
	}
	for(i=1;i<=x;i++)
	for(j=1;j<=y;j++)
	{
	for(k=1;k<=z;k++)
	{
	lin[k]=lin[k-1]+tu[i][j][k];
	xx[i][j][k]=xx[i][j-1][k]+lin[k];		
	}
   }
		for(i=1;i<=y;i++)
	for(j=1;j<=x;j++)
	{
	for(k=1;k<=z;k++)
	{
	lin[k]=lin[k-1]+tu[j][i][k];
	yy[i][j][k]=yy[i][j-1][k]+lin[k];		
	}
   }
			for(i=1;i<=z;i++)
	for(j=1;j<=x;j++)
	{
	for(k=1;k<=y;k++)
	{
	lin[k]=lin[k-1]+tu[j][k][i];
	zz[i][j][k]=zz[i][j-1][k]+lin[k];		
	}
   }
	for(i=1;i<=x;i++)
	for(j=1;j<=y;j++)
for(a=min(x-i,y-j);a>=0;a--)
{	if(4*(a+1)*z<=ans)break;
qi=0;
	for(k=1;k<=z;k++)
	{
if(4*(z-qi+1)*(a+1)<=ans)break;
if(zz[k][i+a][j+a]-zz[k][i-1][j+a]-zz[k][i+a][j-1]+zz[k][i-1][j-1]==(a+1)*(a+1))
{
	ans=max(ans,4*(a+1)*(k-qi));	
}else  qi=k;
	}		
}
	for(i=1;i<=y;i++)
	for(j=1;j<=z;j++)
for(a=min(y-i,z-j);a>=0;a--)
{	if(4*(a+1)*x<=ans)break;
qi=0;
	for(k=1;k<=x;k++)
	{
if(4*(x-qi+1)*(a+1)<=ans)break;
if(xx[k][i+a][j+a]-xx[k][i-1][j+a]-xx[k][i+a][j-1]+xx[k][i-1][j-1]==(a+1)*(a+1))
{
	ans=max(ans,4*(a+1)*(k-qi));	
}else  qi=k;
	}		
}	
	
	
	for(i=1;i<=x;i++)
	for(j=1;j<=z;j++)
for(a=min(x-i,z-j);a>=0;a--)
{
	if(4*(a+1)*y<=ans)break;
qi=0;
	for(k=1;k<=y;k++)
	{
if(4*(y-qi+1)*(a+1)<=ans)break;
if(xx[k][i+a][j+a]-xx[k][i-1][j+a]-xx[k][i+a][j-1]+xx[k][i-1][j-1]==(a+1)*(a+1))
{
	ans=max(ans,4*(a+1)*(k-qi));	
}else  qi=k;
	}		
}	
	printf("%d",ans);	
}



正解是单调栈。。

首先先选一个为底面,  把 他分成好几层    然后再枚举矩形右下角坐标,,这时候暴力的做法就是枚举正方形大小,然而这样做忽略了

整体满足,部分也满足  的性质。所以对于一个正方形,若以n为边长合适,则以1~n为边长也一定合适

所以就在这一个线所在点的矩形最大的n都考虑进来,就相当于



AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 155
int k,i,j,zuo[N],you[N],f[N][N][N],sta[N],top,ans,x,y,z;
char tu[N][N][N],tu2[N][N][N];
void work(int z,int x,int y)
{
	for(k=1;k<=z;k++)
	{
	for(i=1;i<=x;i++)
	{
	for(j=1;j<=y;j++)
  {
  	if(tu[i][j][k]=='N')f[k][i][j]=min(f[k][i-1][j-1],min(f[k][i-1][j],f[k][i][j-1]))+1;  	
 else f[k][i][j]=0;
  }		
	}	
    }
		for(j=1;j<=x;j++)
		for(k=1;k<=y;k++)
		{
memset(zuo,0,sizeof(zuo));
top=0;
sta[0]=0;
for(i=1;i<=z;i++)
{
	while(top&&f[sta[top]][j][k]>=f[i][j][k])--top;
zuo[i]=i-sta[top];
sta[++top]=i;
}		
	memset(you,0,sizeof(you));
top=0;
sta[0]=z+1;
for(i=z;i>=1;i--)
{
	while(top&&f[sta[top]][j][k]>=f[i][j][k])--top;
you[i]=sta[top]-i;
sta[++top]=i;
}
for(i=1;i<=z;i++)
if(tu[j][k][i]=='N')ans=max(ans,(zuo[i]+you[i]-1)*4*f[i][j][k]);			
}
}
int main()
{
	scanf("%d%d%d",&y,&x,&z);
	 for(i=1;i<=x;i++)
	 for(j=1;j<=y;j++)
	 for(k=1;k<=z;k++)
	 {
	 	scanf("%c",&tu[i][j][k]);
		while(tu[i][j][k]!='N'&&tu[i][j][k]!='P')scanf("%c",&tu[i][j][k]);
		tu2[i][j][k]=tu[i][j][k];	 	
	 }
work(z,x,y);
	 for(i=1;i<=x;i++)
	 for(j=1;j<=y;j++)
	 for(k=1;k<=z;k++)
	 {
		tu[j][k][i]=tu2[i][j][k];	 	
	 }
work(x,y,z);
	 for(i=1;i<=x;i++)
	 for(j=1;j<=y;j++)
	 for(k=1;k<=z;k++)
	 {
		tu[i][k][j]=tu2[i][j][k];	 	
	 }
work(y,x,z);	
	printf("%d",ans);	
} 








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值