CF div2 1005 (A~D)

A

每次将当前 s 中以最左侧的连续一段 1 开头的后缀移动到 t,在 t 中留下这段 1,将剩下的后缀再移回 s,循环模拟即可。

code

B

容易发现分数一定不会增加,只能尽可能保持不变。而题中还要在在分数最大情况下最小化数组长度,可以发现:只能删掉出现次数为 1 的数,否则若删去出现次数 >1 的数,分数必然减小,一定不如不删更优。而只能删其中一个子数组,则找出现次数为1的最长连续段即可。

code

C

一眼题。发现选择的任意正数一定在任意负数左侧,则相当于挑选一个左侧全是正数,右侧全是负数的最优子序列。

前缀和分别处理正数和负数,枚举分界位置即可。

code

D

字典树

题目相当于给点 x,求一个最大的 i[1,n1],使得 a[i]>sufxor[i+1]x

首先,通过二进制形式来判断 a>b 的方式:存在第 i 位:

  1. ai=1bi=0
  2. 对于任意 j>iab 的第 j 位均相同。

可以发现这个信息与 相同前缀 是密切相关的,因此可以考虑字典树来维护。这里字典树维护的信息描述起来可能不是很好懂:

  • 字典树上的某个结点 u 对应一个前缀 pre,同时具有一个权值 w[u],表示 x 的前缀为 pre 时,原序列中的哪个位置开始出现 a[i]>sufxor[i+1]x,也就是从 pre 的末位(假设是第 j 位)开始出现 aj=1sufxor[i+1]jxj=0,并且 w[u]=i

a=a[i]b=sufxor[i+1],考虑找到所有满足上述条件的 aj,bj。对于某一对 (a[i],sufxor[i+1]),同时从高到低看它们的每个二进制位。在第 i 位往前的 前缀 相同的情况下(在字典树内对应向下走若干步,走到了某个结点):

  1. aibi (第 i 个二进制位上的数字)相同,则需要继续看后面的二进制位 -> 在字典树中等价于开一个新点并将指针移向这个新点。
  2. 若不同,则当 ai=1bi=0 时,找到了一个符合要求的位置,需要做记录 -> 在字典树中体现为:在对应前缀的结点上记录该位置(若原来有位置,则取最大值,因为要找最先不合法的位置;并且以后再碰到有记录的点就也可以不用再继续看了);而当 ai=0bi=1 时,就不需要看后面的二进制位了,因为一定能保证 a<=b -> 在字典树中等价于什么都不做。(目的是找到所有满足上述条件的位置并在相应前缀上做记录,发现后续不可能再满足上述条件就不需要再开点继续向低位看了)

将所有 (a[i],sufxor[i+1]) 对应全部 x 可能的情况插入字典树后,每个询问可 O(logV) 来处理:

对于任意询问 x,直接跑一下字典树,在路径上经过的结点权值的最大值即为 原序列中最先满足 a[i]>sufxor[i+1]x 的位置 i。具体细节见代码。

code1

还有一个比字典树更好且更易理解的做法,是b站up主yvbf的做法,听完讲解后大彻大悟,感觉是非常好的方法。这里直接贴代码和讲解视频链接,不写题解了。

tutorial
code2

posted @   jxs123  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示
主题色彩