Loading

P6663题解

P6663

某人场上写了:

for(int k=j-1;k>=1;k++){
    pd((edge){k,l,k,l+1});
}

导致挂 40 pts。

题意

n×m 的网格图,构造出一棵树,要求每个格子都在树上,且树的直径为 d。可能无解。

n,m1000,k106

Sol

先考虑无解的情况,即 n,m 对于 d 的限制。直径最大值是好构造的,即所有点形成一条长度为 nm1 的链,画出来长成这样:

再考虑下界,由于最左上角和右下角是联通的,因此至少也应该是 (n1)+(m1)。先尝试直接构造出来一种最小直径的方案:

但这个结论并不正确,不论是通过手玩还是对拍会发现,这种情况可以存在当且仅当 m 或者 n 是奇数的情况,即我们能够找到从中间劈开来的一列。如果两个都是偶数,找不到,因此应该是如下图的 (n1)+(m1)+1 的下界。

判断完界限之后,考虑如何构造的问题。我们可以从直径最小的情况出发,看有没有方法能够每一次给直径 +1 最终达到直径最大的情况。由于奇数的情况简单,先从奇数入手。参照最大直径的情况,尝试每一次改变一条边,让直径增大。

按照这种翻转操作(当然有非常多的改变方法,这仅仅是本人考场上想到的,不代表最优方法),对于分割线右边从左到右翻转,可以做到每次对于答案增加 1,并且不会影响到其他的结构。对于左边同理,这样做完刚好可以回到直径最大的情况。

最后考虑偶数的情况,其实是类似的,只是多了中间的一条边。先考虑移动中间的一条边(即图三的橙色边),每次平移都会让答案增大 2。那么只需要开始先移动这条边,之后再做与奇数相同的操作即可。

总结,先判断是否有解,之后看 n,m 是否都是偶数,如果不是就找到奇数的那个数并从中劈开,然后模拟从最小直径每次翻转边 +1 的过程。如果都是偶数,先用中间的边每次 +2,最后通过与奇数操作一样的来调整 +1

这道题难点可能就在于代码实现上面了。

考场代码

posted @   Jryno1  阅读(24)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示