[TK] 三角蛋糕 hzoi-tg#261

同机房大佬也写了这道题的 题解.

我在另一篇 题解 中提到了这类问题的通解,接下来我们依照此通解思考该题.

问题处理

首先我们来定义三角形的表示方式. 定义 \(f[i][j]\) 表示三角形 \((i,j)\) 的最大边长,其中三角形 \((i,j)\)垂直顶点坐标为 \((i,j)\) 的三角形. (垂直顶点指正下方顶点或正下方顶点)

进行初始化:使所有完好的蛋糕块所在坐标的最大边长都为 \(1\) .

然后进行状态转移方程的推理:
为了坐标便于表示,我们先把蛋糕左对齐,如图.

101100001
 0000010
  00010
   010
    0 
101100001
0000010
00010
010
0 

再放一个比较直观的图:
image

对应着来看,我们发现,正三角和倒三角的处理方式是不同的,所以我们一个一个解决.

先来看倒三角,也就是它的顶点在最上方. 我们发现,要想使边长从 \(1\) 变为 \(2\) ,需要这个三角形的正上方,左上方,右上方都是完好的. 左对齐来看,需要完好的就是正上方,右上方和更右边的一个.

注意到这个图中有一个边长为 \(3\) 的倒三角形,那么我们如何从 \(2\) 变为 \(3\) 呢? 依照刚才的思路,我们发现只需要保证此三角形和它上方的三角形完好,并且它左上方,右上方的三角形的最大边长都为 \(2\) . 也就是下图这样.

image

标蓝的为最大长度为 \(2\) 的三角形,标红的为需要完好的三角形.

发现一定理:假如一个三角形和它上方的三角形都完好,且左上方,右上方的三角形均不大于 \(n\),那么这个三角形的最大边长为\(n+1\).

由此,对应左对齐坐标,推出状态转移方程:

\[f[i][j] = min\begin{cases} f[i-1][j]\\f[i-1][j+2]) \end{cases}+1 \]

同理,正三角的状态转移方程为:

\[f[i][j] = min\begin{cases} f[i+1][j]\\f[i+1][j-2]) \end{cases}+1 \]

找出最大值即可

另外. 如何判断一个三角形是正三角还是倒三角呢? 其实也很简单:顶点是正三角的三角形就是正三角. 而我们左对齐的意义就出现了:可以发现,奇数列的顶点全是倒三角,偶数列的顶点全是正三角,所以遍历的时候直接遍历所有奇数列或偶数列即可.

细节处理

注意到:第一行的顶点无法构成倒三角,最后一行的顶点无法构成正三角,第二列的顶点无法构成正三角. 遍历的时候直接跳过即可.

代码实现

点击查看代码
	cin>>n;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=(n-i)*2+1;++j){
			scanf("%1d",&f1[i][j]);
			f2[i][j]=f1[i][j]=!f1[i][j];
		}
	}
	for(int k=1;k<=2;++k){
		for(int i=2;i<=n;++i){
			for(int j=1;j<=(n-i)*2+1;j+=2){
				if(f1[i][j]&&f1[i-1][j+1]){
					f1[i][j]=min(f1[i-1][j],f1[i-1][j+2])+1;
					ans=max(ans,f1[i][j]);
				}
			}
		}
		for(int i=1;i<=n-1;++i){
			for(int j=4;j<=(n-i)*2+1;j+=2){
				if(f2[i][j]&&f2[i+1][j-1]){
					f2[i][j]=min(f2[i+1][j],f2[i+1][j-2])+1;
					ans=max(ans,f2[i][j]);
				}
			}
		}
	}
	cout<<ans*ans;
posted @ 2024-02-16 10:27  HaneDaniko  阅读(24)  评论(0编辑  收藏  举报