2021.12.6 模拟赛
努力不咕。
T1
巨大多细节题,还不给大样例,我花了三个多小时写了三份代码(爆搜 + \(n^3\) + \(n^2\log n\))为了对拍。
首先没有字典序的限制的话,每行的贡献就是错排数。
逐位 DP,钦定一个前缀相等,当前位 \(<a_{i,j}\)。
那么就要维护后面有多少个有限制的,多少个无限制的;\((i,j)\) 能填的有多少个有限制的,多少个无限制的。用树状数组之类的维护一下,细节很多。
假设后面有 \(a\) 个有限制,\(b\) 个无限制的,方案数二项式反演一下可以得到
,后面的行的贡献还是错排数。可以做到 \(\mathcal O(n^3)\)。
拆一下式子,
枚举 \(b\) 做 \(n+1\) 次加法卷积,可以 \(\mathcal O(n^2\log n)\)。
后来才知道这个东西可以直接递推,考虑最后一个(一定合法)放哪里:
我真是太笨了。
T2
先写个不知道怎么算复杂度的假做法,目前被叉。
按权值从小到大考虑,将所有区间按照包含该权值的个数分类,找第 \(k\) 大所在分类递归下去。
具体实现的话,一个左端点所对应的所有右端点是按照包含关键点个数分段的,只需要每个左端点记录对应的右端点区间;按关键点划分区间,可以在位置集合上二分。
求教怎么算复杂度 /kel
std 正解解读:
第 \(k\) 大问题还是考虑二分答案,有几个问题:
- 找什么样的区间作为关键值来划分?
- 如何维护二分范围?
- 如何快速比较每个区间和关键值?
肯定不能直接记录所有区间是什么。观察单调性,对于一个左端点 \(l\),区间的权值随 \(r\) 增大而增大。那么 \(l\) 所对应的合法区间集合,其右端点也是一个区间。
然后我们随机挑选一个区间作为关键值,容易理解二分次数依旧是 \(\mathcal O(\log n)\) 次。
注意为了均匀随机,也就是对于序列 \(a_{1\dots n}\),选中 \(a_i\) 的概率要是 \(\frac{a_i}{a_1+a_2+\dots a_n}\)。
然后的问题是要划分当前的二分范围。假设我们得到 \(l\) 对应的最大的 \(r\) 使得区间 \([l,r]\) 不大于关键值,那么从 \(l\) 到 \(l+1\),\(r\) 一定是单调不降的,双指针即可做到只用比较 \(\mathcal O(n)\) 次。
要快速比较比较每个区间和关键值。每个区间的权值可以记录为序列 \(c_{1\dots n}\),表示 \(i\) 权值出现 \(c_i\) 次,那么比较大小就是比较字典序。两个区间的权值作差,找到第一个不为 \(0\) 的位置即可比较大小,那么用 \(\texttt{std::set<>}\) 维护 \(c\) 中所有不为 \(0\) 的位置,双指针过程中增量修改,这部分复杂度 \(\mathcal O(n\log n)\)。
总复杂度 \(\mathcal O(n\log^2 n)\)。
T3
NOIP 前考过的原题,当时没改,今天就尴尬了。
具体来说横竖冲突的问题考虑最小割。先让所有点都选上最大的,算进答案,网络流的边流量就是最大值与当前点权值之差,求最小割。
将网格拆成两层图来限制单向的方向,两层图中对应的点用 \(+\infty\) 的边连接来限制不能同时被两者占有,边权就好说了。