Loading

11 月杂题

1.CF1924B Space Harbour

记左侧第一个关键点为 \(l\),右边第一个关键点为 \(r\),这个点的权值为 \(v_l\times (r-i)\),发现对于一部分连续的点,它的左边和右边的关键点都是相同的,唯一不同的就是 \(i\),将这个式子拆开 \(v_l\times r-v_l\times i\),用线段树维护每个点的 \(v_l\)\(r\),当插入一个关键点时,找到它前面一个关键点和后面一个关键点,记为 \(pre,nxt\),此时的修改操作就是把 \([pre+1,x-1]\)\(r\) 修改为 \(x\),把 \([x+1,nxt-1]\)\(v_l\) 修改为 \(v_x\),线段树维护起来不算太难。

2.CF1657F Words on Tree

权且复习一下 2-SAT,2-SAT 的逻辑就是如果选了条件 A 后与条件 B 矛盾,那么条件 A 向条件 B 的反命题连边,此处的连边表示做了一项决策后必须做后面的那一项,在 2-SAT 问题中是有条件真假的判断的,在这个问题中,条件的真假就是路径选取的正反以及字符的选取,被问题路径覆盖的点至多只有 2 种选择,这个比较好证明,在一条路径当中,一个节点只有正反两种情况,根据节点字符的选取决定路径的选择,又根据路径的选择确定节点字符的选择,这样就变成了一个完备的 2-SAT 问题,特别的难写。

3.P4785 [BalticOI 2016 Day2] 交换

观察到操作是一颗完美二叉树的形式,就是类似于线段树的标号方式,每个点 \(p\) 可以与 \(p\times 2\),或者与 \(p\times 2+1\) 进行交换,记节点权值为 \(A\),左儿子权值为 \(B\),右儿子权值为 \(C\),贪心的角度肯定要让节点权值最小,当 \(A\) 为最小时,肯定不用交换,继续执行左右儿子即可,当 \(B\) 为最小时,由于顺序问题,只能交换 \(A,B\),因此结构仍然是固定的,交换后执行左右儿子即可,当 \(C\) 为最小时,\(A,B\) 的左右儿子不能确定,暴力找两个当中最小值的最优位置,暴力用 map 优化一下,找最优位置的逻辑跟上面一样。

4.CF1238E Keyboard Purchase

费用提前计算很好的一个例子,字符集大小上限不传统,应该是在这方面做文章,预处理出 \(c_{i,j}\) 表示字符 \(i\) 与字符 \(j\) 相邻的数量,问题变成确定键盘,换句话来说就是确定字母的顺序,用状压一个一个加入,记 \(f_S\) 表示确定前 \(|S|\) 个字母为 \(S\) 集合目前所得到的最小代价,但是字符并没有确定,这个代价又是怎么计算的呢?不难发现两个字符的代价为 \(|v_i-v_j|\times c_{i,j}\),意思就是存在一个相减的关系,将贡献拆开,统计 \(v_i\times c_{i,j}\)\(-v_i\times c_{i,j}\) 的贡献,比方说 dp 目前的集合是 \(S\),要新加入一个字符 \(i\),那 \(S\) 都是在 \(i\) 前面的,假设 \(A\) 为总集,那 \(A-S\) 都是在 \(i\) 后面的,此时贡献为 \((|S|+1)\times i\times p_{i,S}-(|S|+1)\times i\times p_{i,A-S}\),至于 \(p\) 的转移可以参照高维前缀和的方式,复杂度为 \(\mathcal{O}(n+m2^m)\),可以稳定通过。

5.CF1221F Choose a Square

正方形在 \(y=x\) 上是一个很好的突破口,经典的套路钦定一个点然后算另外一边的最大值,在这里直接钦定左下角,现在要做的就是如何加入点了,加入的点要满足 \(x\ge l,y\ge l\),不妨先让 \(x\ge l\) 加入到优先队列当中,优先队列以 \(y\) 降序排列,然后在看优先队列里面的 \(y\ge l\) 的进行加入,这里的 \(l\) 也要倒着扫。处理完了扫描与加入的问题,然后就是一个点对哪些右上角有贡献,很明显就是 \(\max(x,y)\sim +\infty\),把贡献加入到线段树里就好了。然后就是边长的问题,把出现过的 \(x,y\) 放到提前建立好的线段树,提前赋一个负的贡献即可,当然这里引入一个结论,就是这个最优正方形如果覆盖了点,那肯定最外围有点,不会出现最外围是空的情况,不然为什么不缩减一圈减少边长。

6.CF1743G Antifibonacci Cut

先不考虑空间,发现斐波那契串至多只有 \(\log m\) 个,可以提前预处理出来然后记录一下哈希值,然后设 \(f_i\) 表示前 \(i\) 位分割的方案数,比较显然的枚举最后一个可能的斐波那契串的长度,判断它与真正的那个哈希值想不想等即可,时间复杂度 \(\mathcal{O}(n\log m)\),空间开不下一点。上面这个方法只用到了斐波那契数的级别的关系,不过这个是字符串,它在组成和也包含有性质,\(S_i=S_{i-1}+S_{i-2},S_{i-1}=S_{i-2}+S_{i-3}\rightarrow S_{i}=S_{i-2}+S_{i-3}+S_{i-2}\),发现这个 \(S_{i-2}\) 变成了 \(S_i\) 的 border,而且是最长的。记 \(t\) 为目前位置,用一个 vector 记一个目前仍然是斐波那契串的前缀的东西,记录 \((i,j)\) 表示 \(i+1\sim t\) 仍然是一个斐波那契串的前缀,\(j\) 是它需要减去的答案,现在加入 \(s_{t+1}\),会发现这个斐波那契串的前缀在增加而且是相等的,每次减去一个最大的能减的 \(f_i\) 就可以求到第 \(i\) 位是 \(0/1\),然后判断是不是一个斐波那契串,最后减去即可,然后又更新。

7.CF1743F Intersection and Union

拆位统计贡献,考虑一个位置的贡献,一个位置在所有集合中的情况无非是出现过或者没有出现过,即为 \(0/1\),题目中的三种操作正好可以转化为与、或、异或三种位运算操作,问题变成了求在一堆 \(0/1\) 之间加操作,使最后的结果为 \(1\) 的方案数,发现最后一个 \(1\) 是关键的,在这个 \(1\) 之后的所有操作只能执行异或或者或操作,另外它的前一个操作也只能执行两种,而其它可以执行三种,问题变成了求每个数最晚出现的位置,用线段树维护区间最大值即可。

8.CF2026F Bermart Ice Cream

当复习双栈维护回退背包了,将操作可持久化,就是建立一棵操作树,遍历该树,问题变成求维护一个队列背包,我们知道栈是非常好维护一个背包的,但是队列涉及到前面元素的加减,那就用两个栈维护队列,记录一个左栈和一个右栈,前端操作就在左栈做,后端操作就在右端做,如果在 pop 的过程中操作的那个栈为空,就把另一个栈分一半过来,复杂度是对的,然后套路写就好了。

9.CF2025F Choose Your Queries

这个题带来的启发意义就是思考图论题的时候除了想那些常见算法,还有 dfs 树这个很基础的东西。假设一个点被执行 \(x\) 次,可正可负,贪心肯定是一正一负交替进行,当 \(x\) 为奇数时,贡献产生 \(1\),否则无贡献,问题可以转化为给边定向,使得入度为奇数的点最小。记 \(c_i\) 表示 \(i\) 点连接的边数,在一个连通块中,答案下限为 \((\sum_{i}c_{i})\bmod 2\),考虑构造这样的方案,具体地,从根节点开始执行 dfs,遍历没有遍历的儿子,保证遍历结束后除了本身子树内的点都是偶数,遍历过程中如果自己的孩子有奇数,那就把边连向孩子,否则连向自己,遇到返祖边,把边连向深度更浅的那头,如此执行下来,就可以保证至多只有根节点产生贡献,注意一点,dfs 树中除了树边一定就是返祖边。

10.CF1879F Last Man Standing

如果给一个 \(x\),怎么算每个人的存活的轮数,很显然是 \(h_i\times \lceil\frac{a_i}{x}\rceil\),统计下来每个人的轮数,然后操作就是找次大值与最大值,然后将最大值的编号更新为最大值与次大值的差,\(x\) 至多为 \(\max\{a\}\) 才有意义,所以 \(x\) 实际上是 \(\mathcal{O}(n)\) 级别的,主要就运用到了 \(\sum \frac{n}{i}\)\(n\ln n\) 级别的,所以有将数组按照 \(a\) 排序后然后有很多 \(\lceil\frac{a}{x}\rceil\) 是相等的,然后一段一段枚举相等的再找 \(h\) 最大的,更新最大与次大值即可,可以用 st 表维护最大值与次大值。

11.CF1809F Traveling in Berland

断环为链,然后贪心,\(s\rightarrow t\) 的情况,假设当前油量为 \(o\),设当前走到 \(t\) 还需要 \(e\) 的油量,如果 \(b_i=1\),肯定加油加到上限,也就是 \(\min(k,e)\),如果 \(b_i=2\),油不够加到够就行了,复杂度为 \(\mathcal{O}(n^2)\),发现一个关键,如果从 \(s\rightarrow t\) 的路上全是 \(b_i=2\),那代价就是 \(2d\),那如果起点是 \(b_i=1\),当 \(d\le k\) 时,贡献就是 \(d\),否则是 \(2d-k\),这启示我们把 \(b_i=1\) 的点作为关键点,一步一步跳到 \(b_i=1\) 的点,然后最后一步跳到终点,维护每个点到它下一个 \(b_i=1\) 的贡献,发现这个会被卡,所以倍增搞一下,带一只 \(\log\),似乎有双指针做法可以做到,但是我不会。

12.P10083 [GDKOI2024 提高组] 不休陀螺

找一下条件符合条件的区间的性质。首先 \(\sum_{i}b_i-a_i\ge 0\),如果 \(<0\),那经过若干次操作后就不行了。将那些做负贡献即 \(a_i>b_i\) 的负贡献累加记为 \(s\)\(e-s<\max_{i=1}\big\{\min(a_i,b_i)\big\}\) 时也不合法,所以问题转化为求满足 \(\sum_{i}b_i-a_i\ge 0,e-s<\max_{i=1}\big\{\min(a_i,b_i)\big\}\) 的区间数量,第二个条件在钦定一个端点的情况下很明显是有单调性的,所以枚举 \(l\),然后指针移动 \(r\),并用树状数组记录前缀和。

13.P4654 [CEOI2017] Mousetrap

把陷阱点定为根,先预设一下老鼠有可能走过的路线:向下走,走到叶子,然后走不动了,管理员堵上叶子到根的链的其它儿子,然后帮它清理叶子到根的路径,然后它一步一步走到根;另外一种情况,老鼠先向根走几步,然后又像第一次那样走叶子,后面过程就比较重复了。不妨先考虑第一种情况,即老鼠在 \(u\) 点开始向下走,然后把它赶回到 \(u\) 点要操作的次数,记这个值为 \(f_u\),老鼠肯定会走 \(f_v\) 最大的儿子 \(v\),所以把 \(u\rightarrow v\) 堵住,老鼠就只能走 \(f_v\) 次大的 \(v'\) 了,老鼠从 \(v'\) 走下去,最后也从 \(v'\) 回来,首先 \(u\rightarrow v'\) 的这条路径应该给它清理干净,其次不能让它回到 \(u\) 后走到其它儿子去,所以要把 \(u\) 的其它儿子堵住,综上:\(f_u\gets f_{v'}+d_u-1\),其中 \(d_u\) 为度数。然后算第二种情况,首先把老鼠的位置到根的路径提取出来,把该路径记为 \(r\),记录 \(h_i\) 表示老鼠从 \(r_i\) 开始要封上面多少条边才能使老鼠直接到达根,\(h_i\gets h_{i+1}+d_{r_i}-2\),一个是排除自己的父亲,另一个是排除自己下面的在链上的点,\(h_1\) 没有在链下的点所以要加一。好像没有什么思路了,所以这个题有点不自然的地方就是二分,如果不特意提示是真不会往这方面想。毕竟答案有单调性,操作次数越多肯定更容易成功。二分操作次数 \(p\),然后就枚举从老鼠开始的位置向上的链即 \(r\),记为 \(u\),记录当前已经封的边数 \(c\),以及总的封边数 \(b\),找到 \(u\) 不在链上的儿子 \(v\),如果 \(f_v+h_i>p\) 说明如果走了这个儿子操作次数就不够用了,就要把这个儿子封掉,\(c\gets c+1\),统一遍历完后 \(p\gets p-c,b\gets b+c\),判断 \(b>i,p<0\) 即可。

14.P3724 [AHOI2017/HNOI2017] 大佬

最重要的是第一步,分开自己的自信值和掉对方的自信值,发现这两个东西是不相关的,如果有 \(x\) 天都在做与掉对方自信值相关的操作,这 \(x\) 天肯定是可以任意分配的。但是自己的自信值掉不掉的完就与天数的选择有关系了,所以 dp 出最大的掉对方信心值的天数,可以做到 \(\mathcal{O}(nk)\),记这个数为 \(d\),然后就可以搜索了,搜出花多少天可以掉对方多少信心值的所有对 \((x,y)\),分别表示天数与掉的信心值数,\(y\) 相等的贪心保留 \(x\) 更大的,然后直接枚举这个对,然后二分或者双指针找另一个满足的对,复杂度基于什么,基于这个对数不多。

15.CF2038D Divide OR Conquer

这种类似的题已经做了好多遍了,还是会忘。主要是用了或运算数的变化数量级是 \(\log V\) 的,所以如果钦定一个右端点,那这个或出来也只有 \(\log\) 的级别,总的或起来的数量粗糙一点算也就只有 \(n\log V\),可以用这个写一个 dp,设 \(f_{i,j}\) 表示前 \(i\) 个数最后一段是 \(j\) 的方案数,当然这个 \(j\) 是离散化之后的,利用上面所说的左端点分段这一机制就可以做到 \(n^2\) 的级别,优化直接把这个 dp 的转移放进扫描线里维护就好了。

posted @ 2024-11-04 08:49  AresF  阅读(51)  评论(2)    收藏  举报