国外训练试题泛做
\(36th\ Petrozavodsk\ Programming\ Camp , 300iq\ contest\ 3\)
\(F\)
首先如果选择 \(i\) , 记花费在 \(i\) 上的有 \(r_{i}\) 次 , 则 \((h_{i} - r_{i} \cdot a)\ mod\ b < a\)。
发现 \(r_{i} = \lfloor \frac{(h_{i}\ mod\ b)}{a} \rfloor\)。 那么得分至少要花费 \(r_{i} + 1\) 次。
注意到如果选择 \(i\) 个物品也只需花费 \(r_{i} + 1\) 次 , 因为多花费显然不优。
那么就有一个反悔贪心的思路了。 每次假定不选择 , 将决策放入小根堆 , 每次将堆顶与当前的决策比较即可。
时间复杂度 : \(O(NlogN)\)
\(J\)
首先每个点可以看成一个线性同余方程 , 因此这个题目的本质是求一个线性同余方程组的自由元个数。
任取一棵生成树 , 注意到在非树边确定的情况下树边的权值是确定的。 并且每个点权值向上的贡献是一个正负交替的形式。 因此还要
额外保证奇数深度和偶数深度的点权和相等。 这里的 "点权" 指的是相邻的边权和。
换言之 , 就是对于一个连通分量 , 如果它是二分图 , 那么贡献是 \(2 ^ {|E| - |V| + 1}\) , 否则是 \(2 ^ {|E| - |V|}\)。
时间复杂度 : \(O(N)\)
\(I\)
每个数被统计当且仅当这个数没有 \(a_{1} \oplus a_{2} ... \oplus a_{i - 1}\) 中的位。
直接考虑每个数的贡献即可。
时间复杂度 : \(O(NlogV)\)
\(H\)
题目可以抽象为两种操作 :
\(0.\) 在右侧加点。
\(1.\) 在左侧加点 , 向右侧所有点连边。
这样所给的 \(a\) 序列就可以转化为一个 \(0\) 和 \(1\) 的交错操作序列。
注意到最后答案的形式必然是 \(010101010.....\) 这样的形式。
不妨记 \(dp_{i , j}\) 表示考虑了操作序列的前 \(i\) 个操作 , 当前形成了 \(j\) 条链的方案数。
每次如果是在右侧加点 , 那么这个点与当前左侧所有点都没有连边。 有两种决策 :
\(1.\) 单独成一条链。
\(2.\) 添加在之前某条链的末尾。
如果加入的是左侧点 , 那么该点与右侧所有点都有连边 , 有两种决策 :
\(1.\) 什么都不做。
\(2.\) 合并两条链。
这样分析后 , 这个动态规划就很容易转移了。
注意对于一个环而言 , 其正向和反向都被记了一遍 , 所以答案要除以二。
还需减去二元环的个数 , 为 \(\sum{a_{i}}\) 。
时间复杂度 : \(O(N ^ 2)\)
\(B\)
记度数为 \(1\) 的点有 \(x\) 个。
答案为 \(min\{\frac{N}{2} , N - x\}\)。
证明略。
时间复杂度 : \(O(N)\)
\(ICPC\ World\ Final\ ,\ 2020\)
\(A\)
首先只有 \(p\) 值相同的才能改变位置。
于是将两排都按 \(p\) 值从小到大排序。 用 \(std::set\) 维护当前两个集合。 当 \(ap_{i} \neq ap_{i + 1}\) 或 \(bp_{i} \neq bp_{i + 1}\) 时 , 在 \(set\) 里二分构造方案即可。
时间复杂度 : \(O(NlogN)\)
\(G\)
建立反串的 \(AC\) 自动机。 并将询问串也倒着插入。
对于每个给定字符串 , 将其沿着 \(fail\) 树一路的标记都 \(+1\)。
那么最后询问的就是每个终止节点的标记。
树上差分即可。
时间复杂度 : \(O(N)\)