[TopCoder2014Final] FrozenStandings 解法探究

题目链接

简要题意:给出 \(n\) 段从 \(1\)\(n\) 编号的等长区间,保证区间的端点互不相同。区间可以选取其左端点或右端点值作为键值。求将区间按键值从小到大进行排序之后可能出现多少种不同的编号序列。对 \(10^9+7\) 取模。(\(n\le 5\times 10^5\))。

首先要知道序列不同当且仅当存在两编号在序列中的相对位置不同。

将区间按左端点升序排序,则其右端点也形成升序。尝试按排序后顺序进行增量,为求出答案自然想到记 \(f_i\) 为前 \(i\) 个区间任选键值排序能得到的序列的种数。

现在 \(f_i\) 不好求出,可以尝试枚举第 \(i\) 个区间选取了哪个键值。如果选取较大的键值,那么此时能得到的序列种数即为 \(f_{i-1}\),否则可以考虑再记 \(g_i\) 为第 \(i\) 个区间选取了左键值,前 \(i-1\) 个区间任选键值排序后能得到的序列的种数。

那么自然 \(f_i=f_{i-1}+g_{i}-\)\(i\) 选左右键值时均能得到的序列的种数)。分析括号内要求的序列的性质,可以发现这样的序列必须能在 \(i\) 选左键值且排在最后一位的情况下被构造出,并且这也是充分条件。也就是说我们要求在 \(i\) 选左键值且排在最后一位的情况下能被构造出的序列的个数。

这就相当于求所有右端点在范围 \((l_i,r_i]\) 内的区间都选取左端点的情况下能够形成多少种序列。记该范围内右端点最靠左的区间为 \(j\),那么该问题相当于在 \(g_j\) 上插入了若干个端点,而每个端点都可能将 \(g_j\) 原有的某种序列分裂成若干种不同序列。

但我们运气较好,\(g_j\) 的所有序列都满足排在 \(j\) 后的区间选择了它的右端点从而位置固定,所以在 \(g_j\) 后插入的新端点同样位置固定,并不会导致原有序列的分裂,因而该问题的答案就是 \(g_j\),由此终于得到 \(f_i=f_{i-1}+g_i-g_j\)

乘胜追击,我们继续思考 \(g_i\) 如何求得。继续尝试枚举区间 \(i-1\) 的选择。这里由于 \(i\) 选择了左端点,所以所有右端点在范围 \((l_i,r_i]\) 内的区间选取左右端点能得到的序列一定不同,所以枚举后只要进行简单加和。

如果区间 \(i-1\) 选择了左端点,那么与先前的分析相同,我们得到序列种数为 \(g_{i-1}\)。否则我们继续枚举区间 \(i-2\),直到因编号在 \([j,i)\) 的区间均选取右端点而导致要讨论区间 \(j-1\)。不过这时我们可以发现无需枚举,种数就是 \(f_{j-1}\)

由此我们得到 \(g_i=f_{j-1}+\sum_{k=j}^{i-1}g_k\)。再结合 \(f_i=f_{i-1}+g_i-g_j\),在 \(i\) 的增量过程中维护数值单调不降的 \(j\),并在 \(i\)\(j\) 的移动过程中顺便维护 \(\sum_{k=j}^{i-1}g_k\),就能 \(O(n)\) 求出 \(f\)\(g\),而答案即为 \(f_n\)

总时间复杂度 \(O(n+\text{Sort}(n))\)\(\text{Sort}(n)\) 为将 \(n\) 个数进行排序的复杂度。

posted @ 2021-11-04 21:33  林政宇  阅读(149)  评论(0编辑  收藏  举报