ABCEX 刷题记录
ABC212H Nim Counting
先手获胜只需要异或和不为 \(0\) 。用生成函数解决。
对多项式 FWT 把点值求出来,对多项式等比数列求和就相当于对点值等比数列求和。
ABC213H Stroll
第一反应想了个假做法,对边权 \(dft\) 出点值,然后对 \(T\) 个点值做。但是这是一张无向图,而不是 \(dag\) ,所以不能 \(dp\)。
但是每条边的常数项都是 \(0\), 所以可以分治\(ntt\) 。复杂度 \(O(n^2T\log^2 T)\)
ABC214H Collecting
首先可以缩点转成 \(dag\) 。
然后直接拆点建二分图就行。
对于边 \((u, v)\) , 有 \((out_u, in_v, K, 0)\)
对于点 \(i\) , 有 \((in_i, out_i, 1, a_i)\) , \((out_i, T, K, 0)\)
还有 \((S, scc_1, K, 0)\)
然后跑最大费用最大流。复杂度 \(O(nmK)\), 过不去。
然后把点按照拓扑序编号。那么走边 \((i, j)\) 就会损失 \(\sum_{k=i+1}^{j-1} val_k\) , 记 \(sum\) 表示 \(val\) 的前缀和. 考虑最小化损失。
对于边 \((u, v)\) , 有 \((out_u, in_v, K, sum_{v - 1}-sum_{u})\)
对于点 \(i\) , 有 \((in_i, out_i, 1, 0)\), \((in_i, out_i, K, val_i)\) , \((out_i, T, K, sum_n - sum_i)\)
还有 \((S, scc_1, K, sum_{scc_1})\)
答案就是 \(sum_nK - flow\).
跑最小费用最大流就行. 复杂度是 \(O(nmK)\) ,但是因为负权边很少,所以可以优先队列优化spfa,跑的很快。
而一开始的方法不能优化是因为跑的是 最大费用最大流 ,而图上全是正权边。
- 如果图中负权边比较少的话,可以用优先队列优化spfa.
- 通过考虑代价来把负权变成正权。
- 按照拓扑序考虑损失,从 \(i\) 走到 \(j\) 会损失 \(\sum_{k=i+1}^{j-1} val_k\),这个方法适用于所有偏序关系。
ABC215H Cabbage Master
霍尔定理的另一种使用方式:对于任意右部点集合 \(S\),邻域为 \(S\) 的子集的左部点的权值和小于等于 \(S\) 的权值和。
那么只需要做一遍高维前缀和就能求出最少拿走多少球,记为 \(ans1\)。
然后求方案数,枚举从哪个盒子集合里取球 (这个集合里的每个盒子至少取一个球),这个集合合法当且仅当存在一个超集 \(S\) 满足: (邻域为 \(S\) 的子集的左部点的权值和) - (\(S\) 的权值和) \(\leq ans1 - 1\)。至于每个盒子至少取一个球的限制,容斥一下就行了。这些操作都可以用 \(FWT\) 来完成。
ABC216H Random Robots
机器人互相不碰撞的限制可以用 lgv 引理来处理。从 \(x\) 到 \(y\) 的方案数为 \(\binom{n}{y - x}\) 。考虑暴力怎么做,可以暴力枚举每个机器人的终点,然后求矩阵行列式。\(x\) 是从小到大排序的,显然 \(y\) 也是从小到大排序的,不然一定会碰撞。所以可以设 \(f_{i}\) 表示当前 \(y\) 的坐标都 \(\leq i\) 的方案数,如果高斯消元求行列式很难拓展,而 \(n\) 又非常小,所以可以考虑直接枚举全排列,显然每个全排列的贡献是独立的。复杂度做到了 \(O(n\cdot K!)\) , 然后通过状压 \(dp\) 就可以做到 \(O(nK2^K)\) 了。
具体可以设 \(f_{i, s}\) 表示当前 \(y\) 的坐标都 \(\leq i\) ,已经确定的起点集合为 \(s\) 的行列式值。转移有 \(f(i, s) \rightarrow f(i + 1,s)\) 表示没有 \(y\) 的坐标为 \(i\),也可以 \(f(i,s) \rightarrow f(i + 1, s \cup j)\) 表示第 \(j\) 个起点对应的终点下标为 \(i\) ,记得乘上行列式的系数.
ABC217H Snuketoon
设 \(f_{i,j}\) 表示当前事件为 \(i\),坐标为 \(j\) 受到伤害的最小值, 那么有:
\(D_i = 0\) : \(f_{i,j} = \min_{k=j-(t_i - t_{i-1})}^{j+(t_i-t_{i-1})}f_{i,k}+\max(0,x_i-j)\)
\(D_i = 1\) : \(f_{i,j} = \min_{k=j-(t_i - t_{i-1})}^{j+(t_i-t_{i-1})}f_{i,k}+\max(0,j-x_i)\)
发现 \(f_{i,j}\) 一直都是一个关于 \(j\) 的下凸分段函数。用 \(slope trick\) 开两个堆来维护最低点左右两边的斜率就行。
这个取 min 就相当于是把最低点左边的分段函数左移,右边的右移,打全局 tag 维护。然后加分段函数可以直接在堆里 push。
最低点的纵坐标就是答案。维护它就行。
ABC218H Red and Blue Lamps
挺水的一道题,但就是没有做出来,没有想 \(wqs\) 二分。
暴力的做法只要设 \(f_{i,j,0/1}\) 表示考虑了前 \(i\) 盏灯,有 \(j\) 盏是红色的,上一盏是红色/蓝色时报酬和的最大值。直接dp就行。
因为要求有恰好 \(j\) 盏是红色的,而且 \(f\) 有凸性,所以可以直接 \(wqs\) 二分。
ABC221H Count Multiset
考虑如果没有每个数字出现次数小于等于 \(M\) 的限制的话可以直接求整数划分数。如果有了 \(M\) 的限制的话式子就会变成 \(f_{i,j} = f_{i-1,j-1} + f_{i,j - i} - f_{i - (m+1),j - i}\) 区别在于最后这个 \(f_{i-(m+1),j-i}\) , 这是为了减去恰好有 \(M + 1\) 个 \(1\) 的情况,因为如果恰好有 \(M + 1\) 个 \(1\) 的话,所有数都减 \(1\) 就会减少 \(M + 1\) 个数字。这个思想太妙了。思考一下这个方法的本质,其实就是直接减不好减因为根本没有记录恰好有 \(M + 1\) 个 \(1\) 的状态,但是它可以被其他状态转移(不知道转移,表示,求,用哪个词更合适)出来。

浙公网安备 33010602011771号