A
给定 \(n\) 个区间,你要选出最多区间对数,使得每一对的区间都不交。\(n\le 4e5\)。
反悔贪心,我们将所有区间按 \(l_i\) 从小到大排序,一个一个加入,加入的时候有两种情况。
1.之前的区间中存在未匹配的区间,且可以跟当前区间匹配。我们随便选择一个区间跟当前区间匹配即可。
2.找不到可以跟当前区间匹配的未匹配的区间。我们在已经匹配的区间对 \((i,j)\) 中找到 \(r_j\) 最小的一个区间对,如果 \(r_j\) 比当前区间的 \(r\) 小,我们可以交换这两个区间,让 \(i\) 跟当前区间匹配,把 \(j\) 变成未匹配区间。
B
有一个 \(1\sim n\) 的排列 \(a\) 和一个大根堆,你要依此来生成排列 \(b\)。你可以进行两种操作中的一种
i. 将当前 \(a_i\) 插入堆,且 \(i\gets i+1\)。 ii. 将堆顶元素弹出并排到 \(b\) 的末尾。
问生成 \(b\) 的不同的个数。\(n\le 100\)。
好题。设 \(1\) 在 \(a\) 中的位置是 \(p\),在 \(b\) 中的位置是 \(q\),那么 \(p\le q\),考虑枚举 \(q\)。
寻找切入点,不难发现,取出 \(1\) 这个数之后堆一定是空的。所以 \(a\) 与 \(b\) 前 \(q\) 个数的集合相同。
那么很明显就可以划分子任务,将 \(a\) 划分为 \([1,q]\),\([q+1,n]\) 两个段,他们之间是独立的。
其中 \([1,q]\) 这个区间要去掉 \(1\)。注意不是 \([1,q-1]\),因为 \(q\) 是其在 \(b\) 中的位置。
划分了子任务之后,枚举除了 \(1\) 最小值的位置,那么其弹出时堆是空的(忽略 \(1\))。
所以设 \(dp_{l,r,v}\) 表示考虑了区间 \([l,r]\) 里 \(\ge v\) 的数的方案数,复杂度 \(O(n^4)\)。
转移的时候枚举 \(q\),需要保证 \(a_q\ge v\)。因为 \(<v\) 的我们已经忽视掉了,相当于直接删去,没有影响。
这种划分子任务的方式很新颖呢,本来我的想法是前缀划分,但是无法描述一个堆的状态而告负。
C
定义平衡的 01 序列满足任意子区间 01 个数差 \(\le k\),问有 $ n$ 个 \(0\),\(m\) 个 \(1\) 平衡序列有多少个。
\(n+m,k\le 5e7\)。
典题。填 \(0\) 转化为向右走,填 \(1\) 转化为向左走,相当于格路计数。
我们要满足其能被两条 \(y=x+b\),\(y=x+(b+k)\) 的直线包裹住,即不穿过。
考虑枚举这两条直线,然后注意到会算重,所以我们考虑减去 \(k-1\) 的答案。
然后就是经典的反射容斥,复杂度是 \(O(\dfrac{n+m}{k})\),刚好与枚举直线的 \(k\) 抵消了。