【比赛日志】USACO 2020 US Open Contest, Platinum
USACO 2020 US Open Contest, Platinum
Problem 1. Sprinklers 2: Return of the Alfalfa
考虑一个合法的解,容易发现,种植C
的与A
的之间有一条从左上角到右下角折线作为分界线。
对于一个分界线来说,合法解的数量为\(2^{(空余的格子数量-转折的数量)}\)
我们设当前处于\((i,j)\)上方的横向折线,它的方案数为\(f_{i,j}\);设当前处于\((i,j)\)右方的折线,它的方案数为\(g_{i,j}\)。可以有以下转移式:
答案即为\(f_{n,n+1}+g_{n+1, n}\)
- +50min:调试完,过了所有样例。上传:AC
Problem 2. Exercise
+100min:实在想不到怎么优化了,开始写代码。
初步想法
计算出所有的“环”,则所有环的长度的lcm即为要经过的步数。
固定所有“环”,设长度为\(i\)的环有\(a_i\)个,则满足要求的排列的数量为
其中,\(A_i = (i-1)!\)表示\(i\)个数的排列恰好形成一个“环”的方案数。(相当于一个有向的圆排列)
设所有“环”长均为\(x\)的因数的方案数为\(f_x\),所有“环”长的lcm为\(x\)的方案数为\(g_x\),有:
只需要计算出\(f\)即可计算出\(g\)。
如何计算\(f\)?用朴素DP的话,需要存\(lcm,i,a_i,\sum_i ia_i\),复杂度是\(O(n^4)\)的(或者\(O(n^3\log n)\))。
(+100min)……刚刚发现了一件事:所有lcm的数量可能是极大的……根本没法枚举……【自闭】
由于答案要求的是所有步数的乘积,那么能不能求出步数中恰好被\(p^{k}\)整除的个数呢?
若要求出\(g\),则可以枚举所有\(p\)的幂次不超过\(k\)的数进行转移,当\(k'=k+1\)时,直接在原来的背包数组中添加\(p\)的幂次为\(k\)的数即可。
总复杂度应该是\(O(n^4)\)的。
小小优化
考虑用背包的方法处理转移式:设\(f_{i,j}\)表示当前所有“环”长的lcm为\(i\),已经处理了\(j\)个数的方案数。
当环长\(=k\)时,对每一个\(\bmod k\)的剩余系做一个背包即可,复杂度为\(O(n^2)\)。总复杂度是\(O(n^3)\),仍然有点高。
我们考虑计算所有数均为\(k\)的因数的方案,只需要枚举所有\(k\)的因数即可,可以用一维\(g_i\)表示。复杂度是\(O(\sigma_0(k)n)\)的。
总复杂度应该是\(O(n\sum_{k=1}^n\sigma_0(k))=O(n^2\log n)\)的,但是对于\(n=7500\)似乎还是有些无力……
再进一步?
我们考虑一个玄学优化:对于\(k\),我们从\(k/p\)转移过来,其中\(p\)是一个\(k\)的素因数,不妨设是最小的。然而,这也只能将需要计算的数目从\(68093\)优化到\(24245\),还远远不够。
束手无策了……先写起来吧……