251005 模拟赛
T1
给定一个长为 \(n\) 的序列,每次操作你可以选择一个长为 \(k\) 的区间,将区间内数字都删掉,并在原来的位置插入一个数字,其值等于区间异或和。你需要不断操作直到区间长度等于 \(1\)。保证 \((k-1)\mid (n-1)\)。定义一个操作序列的代价为:插入的所有数字的和。最小化操作代价。
\(n\le 500,~k\le 50\)
考虑区间 dp,设 \(f_{i,j}\) 表示把区间内的数字能删就删,最终剩下 \(<k\) 个数字,最小代价和。若 \((k-1)\mid(len-1)\),那么最后一次操作一定是把 \(k\) 个数字合成 \(1\) 个,这时考虑最后一次操作之前。此时区间内还剩 \(2\sim k\) 个元素,枚举第一个元素在原序列中对应的区间,容易做到 \(O(\frac{n^3}{k})\)。
T2
给定一个长为 \(n\) 的二元组序列。有一个排列初始为 \(p_i=i\)。一个二元组表示一个操作:交换排列中位于 \(a_i,b_i\) 的两项。有 \(q\) 次询问,每次询问给定区间 \([l,r]\) 和常数 \(k\),询问从左到右只执行区间内的操作,最终排列的第 \(k\) 项是多少。(询问之间相互独立)。
\(n,q\le 10^6\)
首先容易通过倍增做到 \(O\big((n+q)\log n\big)\)。可以通过本题。
考虑时光倒流,从右到左依次执行每一个操作,那么依次询问等价于询问在执行到 \(r\) 时位于第 \(k\) 项的值在执行到 \(l\) 时位于什么位置。容易做到线性。
T3
发现每个点的答案显然有下界:所有出边 \(r\) 的最小值。发现答案最大的点显然可以取到下界。删掉这个点之后的问题也是容易维护的。
通过维护删边和桶排可以做到线性,但是我不太会。
T4
初始给定一个长为 \(n\) 的序列 \(a\)。一次冒泡排序定义为执行一次以下代码:
有 \(q\) 组询问,每次询问:进行 \(c\) 次冒泡排序之后,区间 \([l,r]\) 的前 \(k\) 小值之和是多少。
\(n,q\le 5\times 10^5\)
官方题解实际上很清楚了,还是建议自己看官方题解思考,实在不知道怎么实现的可以看下面。
先考虑如何求出区间内的第 \(k\) 小值。考虑二分答案,将序列转化为 01 序列。那么一次冒泡排序会将所有 \(0\) 向左移动一位(一段前缀的 \(0\) 不动)。那么最终停留在区间 \([l,r]\) 的 \(0\) 只可能在 \([1,r+c]\) 之间。同时考虑到左边的一些 \(0\) 会溜到 \(l\) 左边,因此分讨 \(c\) 次冒泡之后 \([1,l-1]\) 是否被 \(0\) 填满。发现这时容易判断的,只需查询 \([1,l+c-1]\) 内 \(0\) 的数量。
考虑如何对两种情况分别处理。若 \([1,l+c-1]\) 内 \(0\) 的数量没有填满 \([1,l-1]\),那么 \(0\) 的数量就等于 \([1,r+c]-[1,l+c-1]\)。否则,多出的 \(0\) 都会追加到后面,可以用 \([1,r+c]-(l-1)\) 计算(这里直接用区间表示区间内 \(0\) 的数量了),即使多统计几个 \(0\) 二分答案也不会有什么问题。
二分答案可以直接在主席树上线段树二分,从而做到单 \(\log\)。
考虑如何求前 \(k\) 项和。这里先把第 \(k\) 小的值求出来,记为 \(v\)。注意到若 \([1,l+c-1]\) 内的 \(0\) 填满了 \([1,l-1]\),那么不易计算溢出到 \(l-1\) 后面那些 \(0\) 的 \(sum\)。尝试观察性质,发现 \(c\) 次操作之后 \([1,l+c-1]\) 前缀中的前 \(c\) 大都会移动到 \([l,l+c-1]\) 及 \(l+c-1\) 以后,其中后者不会有什么影响,因为交换过来的数字一定更大。也就是说,\(c\) 次冒泡排序把 \([1,l+c-1]\) 的前 \(l-1\) 小都扔到了 \([1,l-1]\)。这可以再通过一次主席树查询得到。
若 \([1,l+c-1]\) 内的 \(0\) 没有填满 \([1,l-1]\),那么只需要直接减去 \([1,l+c-1]\) 中小于等于 \(v\)(也就是数字 \(0\))的数字之和就行了。实现中可以分两个函数,一个用来找 \(k\) 小值,另一个用来求 \(k\) 小和,后者传入两个参数 \(v\) 和 \(k\),表示取 \(\le v\) 所有数字中的前 \(k\) 小,若不足 \(k\) 个则只取 \(\le v\) 的数字,同时返回一个 \(cnt\) 表示到底统计了多少数字。先查 \([1,l+c-1]\) 的贡献,得到 \(cnt\) 后查 \([1,r+c]\) 中 \(\le v\) 的前 \(k+cnt\) 小。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
|