作战记录(:)
(Day1)
开场大概 (10min) 发现 (A) 是个普及组题,然后切了.
发现 (B) 是个计算几何,这种题对我来说完全不可做,于是写了个 (30pts) 跑路.
然后开始写 (C)
一 档 一 档 打 部 分 分,代码总长11KB,你值得拥有:
(100+30+100=230.)
(Day2)
开场一看这个 (A) ,整出了一个可持久化 (fhqTreap) 的阴间做法,卡空间卡时间,非常自闭.
然后我就卡了 (3.5h) 常数 (,) 才过掉.
然后看了看 (B) ,猜了一个结论,花了 (5min) 写了个 (O(nq)) 暴力,发现对了,然后写了个树剖过掉了.
(C) 是个五合一计数题,我还剩 (1h) 来不及做,就写了个 (51pts) 跑路了.
(100+100+51=251.)
(solution:)
(D1T1)
记 (f(x) = frac{x(x+1)}{2}.)
不难发现答案为 (sumlimits_{i=1}^n f(w_i) * f(h_i)+sumlimits_{1leq l<rleq n} w_lw_rf(minlimits_{i=l}^r(h_i)))
用单调栈优化即可.
(D1T2)
计算几何扫描线题.
首先为了防止出现一些边界情况,(比如有一条无斜率的线段),可以把点转一个角度。
用set维护当前的所有线段,并记录每条线段上方,最晚被插入/删除的后继的线段。
然后从左到右扫描线,
在每次加入线段的时候,考虑把加入的线段的左端点和set里的一个点连接起来。
考虑这个线段在set上的前驱,如果前驱上记录了点,那我就把这个点和记录的点连起来,否则我就和前驱这条线段的左端点连起来。 同时用当前这条线段的左端点来更新前驱记录的点。
在每次删除点的时候,更新一下set上的前驱记录的点即可。
复杂度(O(n log n).)
(D1T3)
首先思考 (D=1) 怎么做.
不难发现,如果一个时空隧道指向了一个必胜点,那么这个时空隧道相当于不存在;否则相当于强制把这一层的某个点 (x) 变为了必胜点.
换根 DP 求出 (cnt_x) 表示能使 (x) 胜负状态改变的强制把这一层的某个点 (y) 变为了必胜点的操作种数.
记原树上的必胜点数目为 (cntw) ,必败点数目为 (cntl) ,记 (win_x) 表示原树上 (x) 是否必胜,是则为 (1) ,否则为 (0) .
那么对于 (D=1) ,答案就是 (cnt_1 imes cntl + win_1 imes n imes cntw) .
记 (fw_i) 为 把 (i) 强制变为必胜点之后的必胜点数目,特别的,令 (fw_0=cntw) . 记 (sumcntw) 为 (sumlimits_{i=1}^n fw_i)
记 (fl_i) 为 把(i)强制变为必胜点之后的必败点数目(,)特别的(,)令 (fl_0=cntl) . 记 (sumcntl) 为 (sumlimits_{i=1}^n fl_i)
对于 (D>1) 的情况(,)首先我们考虑 (dp_{i,x(1leq xleq n)}) 表示第(i)层的时空隧道连接了下一层的必败点(,)并使得(x)强制变为必胜点的方案数.
再记一个 (dp_{i,0}) 表示示第 (i) 层的时空隧道连接了下一层的必胜点的方案数.
如果我们能计算出这些东西(,)那么答案就是 (sumlimits_{i=0}^n dp_{1,i} imes (cnt_1 imes fl_i+win_1 imes n imes fw_i))
那么怎么 DP 呢?
(dp_{i,x(x>0)} = sumlimits_{y=0}^n dp_{i+1,y} imes fl_y)
(dp_{i,0}=sumlimits_{y=0}^n dp_{i+1,y} imes fw_y)
不难发现所有的 (dp_{i,1},dp_{i,2},...,dp_{i,n}) 都相等,所以对于每个 (i) 我们只需要记两个 DP 值.
并且转移可以写成矩阵形式,而且无论是转移还是计算答案我们都不需要求出 (fl_i) 和 (fw_i) ,只需要求出它们的和 (sumcntw) , (sumcntl) . 这两个数可以通过上述的换根 DP 结果求出.
复杂度 (O(n+log D)) 或 (O(nlog n+log D)) 细节非常多.
(O(n + log D)) 代码 :见云剪贴板
注意实现时的空间!!!注意实现时的空间!!!注意实现时的空间!!!
不建议使用vector存图/map存DP结果.
(D2T1)
阴间做法:直接上可持久化 (fhqTreap) 然后暴力.
阳间做法:对时间开一颗线段树记录边存在的位置,查询的时候直接在线段树的祖先节点上找到(x)相邻的所有边即可.
(D2T2)
考虑一个 (O(nq)) 的暴力/结论:
首先,如果叶子节点数目为奇数,则必然无解,返回 (-1).
随便选取一个度数 (>1) 的点 (rt) 为根进行dfs,然后考虑每个子树 (x(x eq rt).)
记 (siz_x) 为 (x) 子树内的叶子节点个数,这个可以在dfs的过程中统计出.
如果 (siz_x) 为奇数,那么 (x) 到父亲的边至少要被清扫 (1) 次.
如果 (siz_x) 为偶数,那么 (x) 到父亲的边至少要被清扫 (2) 次.
证明:
可以发现这个问题是一个把所有叶子节点两两匹配并保证所有树上的边都被覆盖到的问题.
那么,每个子树 (x) (除了根之外)必须要有至少一个叶子 (z) ,它和子数外的另一个叶子进行匹配.
那么如果子树内的叶子数目是奇数,那么我就两两匹配然后留下 (1) 个,否则我就两两匹配然后留下 (2) 个.
因为所有非叶子节点度数 (>1) ,并且每个子树往外匹配的叶子数目只有 (1) 或 (2) 个,所以一定可以成功匹配.
现在我们考虑优化.
答案为 总点数 (-) (2) (+) (sumlimits_{x∈T}[siz_x) 是偶数 (])
这个东西可以直接树剖维护, (O((sumlimits_{i=1}^q D_i)log^2 n).)
也可以用虚树做到 (O((n+ sumlimits_{i=1}^q D_i)log n).)
(D2T3)
这道题分为三个不同的子任务.
subtask1 : (T = 'P'/'R'/'Q')
这个部分直接暴力即可,注意 (T = 'Q') 的部分有一点细节.
subtask2 : (T = 'B')
首先先判掉 (1+R+c1+cr) 是奇数的情况 . 这样的情况必然无解 .
枚举第一步是往左走然后往右走,然后贪心的往下跳,每一步都撞到边界,直到当前坐标 ((x,y)) 满足 (xgeq R,y=cr)
那么我们就求出了最优的步数。
方案数实际上就是考虑,记 (d=frac{x-R}{2}) , (t) 为转弯的次数,即步数 (-1.)
然后相当于在每个转弯的地方我可以缩进去一些距离 ,这些距离的和为 d ,那么这就是一个经典组合问题 , 答案为 (inom{t+d-1}{d}).
因为 d 是多出来的距离 , 不会超过 (O(C)) 级别 , 但是 t 是 (O(frac{R}{C})) 的 , 可能很大 , 所以我们使用 (O(C)) 的方法求组合数 .
那么就能做到每组询问 (O(C)) 查询了 .
subtask3 : (T = 'K')
一个 (O((C+Q)C^2 + Q imes C log C log R)) 做法
(O(C^3)) 暴力dp,然后使用 (O(Q)) 次BM算法求出递推式,总复杂度 (O((C+Q)C^2)) ,每次查询使用【模板】常系数齐次线性递推的科技来查询答案.
优化1:减少跑BM的次数
因为特征多项式 (F) 只有一个,并且只要求 (x^R) 对 (F) 取模的结果,并且 (R) 是一个定值,所以可以先 (O(C^2log R)) 或 (O(C^2+C log C log R)) 的复杂度求出取模之后的多项式,查询的时候直接 (O(C)) 就可以了.
复杂度上线性递推部分少了一个 (O(C)) (,)不过还是需要 (O(C^3)) 的暴力DP,所以复杂度实际上并没有变优.
优化2:优化掉暴力DP的 (O(C^3))
因为前 (C) 步不可能上下同时越界(,)所以就分别容斥掉越上界/下界的情况就可以了.需要 (O(C^2)) DP一下容斥的结果,然后就可以支持 (O(1)) 查询暴力 DP 的结果了.
那么查询还是 (O(C)) ,不过预处理的复杂度从 (O(C^3)) 降到了 (O(C^2))
优化3:优化求特征多项式的复杂度
特征多项式 (F_C=(λ-1)F_{C-1}-F_{C-2},) 所以可以 (O(C^2)) 直接计算,不需要使用BM了.
并且可以发现,把 (n) 个单位根的点值带进去,然后IDFT,就可以直接获得所求多项式的系数,复杂度 (O(Clog C).)
如果使用线性递推的科技,可以获得 (O(C^2 + C log C log R)-O(C)) 的复杂度.
优化4:进一步优化暴力DP解的计算/预处理
EI 对暴力 DP的解解出了一个封闭形式.
理论上可以优化到(O(C log Clog R)-O(C)) 大家快来膜EI
(Theta{(Clog Clog R)} - Theta{(1)}) !