[TK] 三角蛋糕 hzoi-tg#261
同机房大佬也写了这道题的 题解.
我在另一篇 题解 中提到了这类问题的通解,接下来我们依照此通解思考该题.
问题处理
首先我们来定义三角形的表示方式. 定义 \(f[i][j]\) 表示三角形 \((i,j)\) 的最大边长,其中三角形 \((i,j)\) 为垂直顶点坐标为 \((i,j)\) 的三角形. (垂直顶点指正下方顶点或正下方顶点)
进行初始化:使所有完好的蛋糕块所在坐标的最大边长都为 \(1\) .
然后进行状态转移方程的推理:
为了坐标便于表示,我们先把蛋糕左对齐,如图.
101100001
0000010
00010
010
0
101100001
0000010
00010
010
0
再放一个比较直观的图:
对应着来看,我们发现,正三角和倒三角的处理方式是不同的,所以我们一个一个解决.
先来看倒三角,也就是它的顶点在最上方. 我们发现,要想使边长从 \(1\) 变为 \(2\) ,需要这个三角形的正上方,左上方,右上方都是完好的. 左对齐来看,需要完好的就是正上方,右上方和更右边的一个.
注意到这个图中有一个边长为 \(3\) 的倒三角形,那么我们如何从 \(2\) 变为 \(3\) 呢? 依照刚才的思路,我们发现只需要保证此三角形和它上方的三角形完好,并且它左上方,右上方的三角形的最大边长都为 \(2\) . 也就是下图这样.
标蓝的为最大长度为 \(2\) 的三角形,标红的为需要完好的三角形.
发现一定理:假如一个三角形和它上方的三角形都完好,且左上方,右上方的三角形均不大于 \(n\),那么这个三角形的最大边长为\(n+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;