LOJ
感觉这个题十分好玩于是诈尸更博。一年之前的做题心得只有这道题还记得清楚……
设输入为\(n,m\)时的答案为\(f(n,m)\),首先\(f(n,m)=f(m,n)\)所以接下来默认\(n \leq m\)。一件重要的事情是打表得到当\(m>n+1\)时\(f(n,m) = f(n,m-1)*3\),证明不会。
所以最后的问题是快速得到\(f(8,9)\)。\(n,m\)不大考虑搜索。
首先考虑一些没用的剪枝:
1、同一条对角线上填入的数字自底向上不增。这个不难反证得到。
2、如果存在\((i,j)\)和\((i+1,j-1)\)填入的数字相同,那么\((i+1,j)\)与\((n,m)\)构成的矩形中一条对角线上所有位置的值必须相同。也可以反证得到。
我们假设用了这些剪枝可以剪掉绝大部分状态,那么我们考虑如何check一个通过上述剪枝得到的答案是否合法。暴力的复杂度是\(15 \times \binom{15}{8}\)难以接受,我们考虑一些不同的思路。
对于两条路径\(P,Q\),找到第一次分岔的位置,记做\((x,y)\),那么这两条路径中必定一条向右走、一条向下走。不失一般性地假设\(P\)向右走,那么\(P\)得到的二进制串必须比\(Q\)得到的二进制串小。而\((x,y)\)是第一次分岔的位置,所以\(P,Q\)是否满足条件和\((x+1,y)\)以及\((x,y+1)\)作为起点的所有路径的串的\(\min\)和\(\max\)有关。如果能够得到从某个点开始到达终点的所有串的\(\min\)和\(\max\),判断合法就迎刃而解了。
对于求以任意位置作为起点到达终点的串的\(\min\)和\(\max\),考虑DP:设\(f_{i,j,0/1}\)表示从\((i,j)\)到\((n,m)\)的所有串的字典序\(\min / \max\),转移枚举下一步去到哪里。注意到DP的复杂度是\(O(nm)\)的,相比之前有很大的提升。
这样有可能还是跑不进\(2s\),但是注意到下面check合法则上面所有的剪枝都一定满足。如果可以最大化check方式在搜索中的剪枝效果,就可以更快速地搜出结果。
那么可以这样做:按照对角线倒着填数,每一次填入一个位置之后立即计算它的DP值,判断能够判断是否合法的位置,如果某些位置作为第一次分岔的位置已经不合法,则不往下搜。不难发现这样的搜索剪枝是包含了上面的剪枝1、2的,是一个更强的剪枝。这样你就可以在LOJ上以\(200ms\)的速度搜出\(f(8,9)\),问题就完成了。