20251229 - 月度检测 总结
比赛链接:https://vjudge.net/contest/778183。
\(\mathcal{Preface}\)

我罚时是真没吃几发吧。
也确实挺无奈啊。
我如果是准点来的我岂不是 rk1 啊。而且我又多出来 \(50\)min 想 I,没准还能想出来呢。
幸好赶上来了吧也还是。
\(\mathcal{Problems}\)
A
纯水题吧。枚举然后算然后判断就好了。
注意判断三个数 \(x,y,z\) 不同的时候只写 if(x!=y&&y!=z) 是不够的,虽然等号有传递性但不等号没有,所以要再加句 x!=z 才行。
B
日常脑抽看成最小可能代价。
由于要求最大可能代价,那我们尽可能打破规则地去填,于是直接选择让剩余的没被填进去的数组从大到小填进每个空位。可以证明一定最优。
至于后面那个连续段怎么求,这个比较简单的,定义 \(bel_i\) 表示 \(i\) 被填在序列的哪个下标上。然后看前缀和后缀 \(bel_i = i\) 的数量有多少,减掉即可。啊说起来怎么这么别扭
C
啊这个 C 还是有点难度的嗯。
定义 \(a\) 和 \(b\) 两个数组分别为 \(0\) 数组和 \(1\) 数组,公式表达 \(a_{i,0}\) 和 \(a_{i,1}\)。
考虑 DP。定义 \(dp_{i,0/1}\) 表示当前考虑了前 \(i\) 位并且 \(a'_{i,0} = a_{i,0/1}\) 的情况下,下标集合的个数。
那么转移就很简单了啊。首先是枚举 \(i\),其次是 \(x\) 和 \(y\) 分别代表这一波和上一波的 \(0/1\) 情况。定义 \(x'\) 和 \(y'\) 是 \(x\) 和 \(y\) 取反后的。那么你只要判断满足 \(a_{i,x} \ge a_{i-1,y}\) 且 \(a_{i,x'} \ge a_{i-1,y'}\) 时,就做转移 \(dp_{i,x} = dp_{i,x} + dp_{i-1,y}\)。
注意最后的答案需要 \(\div 2\) 因为这个东西可以颠倒,那么就重复算了。用到乘法逆元。
以及时刻记得取模。
D
这个 D 毫无思维量啊。
连通,最小,你想到了什么?答对了,最小生成树。
判相交不用说,直接看两个圆心之间的距离是否小于等于两个半径之和;然后这个魔法回路的长度呢,就是两个圆心之间的距离减去两个半径之和。这里的距离都是欧几里得距离。
那么直接连边做就好了。我这里发现 Kruskal 好像会爆空间,于是采用的 Prim。
E
怎么有人换根做的,太强了。
注意到直接爆搜肯定会炸,那么考虑优化。优化呢,一般就是剪枝或者记忆化。找不到什么好的剪枝啊,那我们就来记忆化吧!
记忆化很简单的,就是记录 \(dis_u\) 表示从 \(u\) 点出发能跑到的点的个数。然后搜的时候如果搜到的某个点 \(v\) 的 \(dis_v\) 已经有值了,那么就直接返回答案不必再搜。
然后从每个点出发搜一次就行了,因为加了记忆化,均摊是 \(O(n)\) 的,活着。
F
咳咳,由于 \(a\) 又是在 \(p\) 的基础上对某个区间的每个数进行 \(+1\) 操作,那么 \(a\) 的 \([1,n]\) 总和减去 \(p\) 的 \([1,n]\) 总和就是这个区间 \([l,r]\) 的长度即 \(r-l+1\)。这里只需要用一次查询,因为 \(p\) 的 \([1,n]\) 总和确定。
接下来呢,我们考虑倍增确定起点。
定义 \(now\) 为当前枚举到的位置,初始 \(now=1\)。枚举 \(i\) 从 \(\log n\) 到 \(0\),然后每次查询 \(a\) 和 \(p\) 中分别在 \([now,now+2^i-1]\) 这个区间的总和。如果这两个和相等,就推进 \(now \gets now + 2^i\),否则不变。最后得到的 \(now\) 就是起点,由于之前又知道了长度,那么区间就很容易得到了。
由于 \(\log n < 20\),那么 \(2 \log n < 40\),再加一个一开始得长度的,也绝对不会超过 \(40\) 次,能过。
G
啊这个真的可以不分层吗。总之我是分层了的。
肯定搜索,拐弯的时候加贡献即可,但是这里记录起来有点麻烦啊——啊你可能直接用标记数组?但这样第一次到的真的是最优的吗,我好像无法证明,所以还是存个 \(dis\) 吧。但是这个 \(dis\) 有点麻烦啊,因为有从多个方向来的人,所以我们给它再分个层,存一下上一次的方向。
依然跑板子 BFS,只是记录多了一维。就做完了。
H
有向图,啊啊,你家强连通分量来找你了。
首先先求出图中所有强连通分量并一一统计入度。啊啊,你会想到,如果某个强连通分量的入度是所有强连通分量个数 \(-1\),那么这个强连通分量里的奶牛一定被所有奶牛喜欢。那就是明星牛了。
对,但是不止啊,你可能是间接喜欢对不对,啊啊,那咋办,你没办法直接用度数来判断了。
怎么办呢?凉拌炒鸡蛋,难吃又难看。
不难想到用一些别的东西来判断,比如 BFS。把整张图缩点——嗯或者说你再以一个强连通分量为一个点新开一张图,然后从每个强连通分量出去跑 BFS,如果遍历到了全局的点这个强连通分量里的牛就都是明星牛了。
嗯,不错,但是之前统计的是入度啊?这里不太对吧?啊啊,是的是的,这个图要反着建一下,当 \(u\) 喜欢 \(v\) 我们连边 \(v \to u\),这样就能从明星牛出发遍历到所有牛了!
于是就过咯。
诶嘿,我一直觉得这题暴力能过啊,一样建反图跑 BFS,\(O(nm)\) 的,也还好啊,\(5 \times 10^8\) 那为啥就跑不过去呢?
——可能因为时间只有一秒加上洛谷评测机老爷机跑不太过去吧。不过在考场上,感觉还是能捞挺多分的。
I
原来我现在连 *\(1800\) 都不会做呢!那我有什么脸说我的实力范围是 *\(1500 \sim 2000\) 呢!
调和级数。
由于原始价格最高 \(2 \times 10^5\),这个是数组存的下的,我们考虑用一个桶记录每种价格的商品个数。然后求一个前缀和,这样就能 \(O(1)\) 得出价格在某个区间内的商品的个数咯。
暴力地枚举 \(x\) 来降价,且最初的收益是 \(- n \times m\),因为你要打印这么多个标签。
然后枚举区间 \([l,r]\),从 \([1,x]\) 开始,区间长度总为 \(x\),并且每次后移都是让 \(l \gets l + x\)。
但是枚举了这个区间有什么用呢。因为是向上取整,所以原价在这个区间的所有商品降价后的价格是一样的都是 \(r \div x\)。
于是我们就可以通过之前维护的前缀和算出该区间内有多少个商品,收益加上。
标签呢?那你就是得看看原来的商品有没有价格是 \(r \div x\) 的,可不可以借用标签了。同样也可以通过之前维护的前缀和得出这一波标签省下的钱。
于是这样就可以算出 \(x\) 来降价的情况下的收益是多少。然后取 \(\max\) 即可。
看起来会超时,但是枚举区间那里是调和级数,所以实质上的时间复杂度是 \(O(V \log V)\) 的,其中 \(V\) 为值域且 \(V = 2 \times 10^5\)。不会炸。
\(\mathcal{Summary}\)
前面的题目都做的不错,但是最后一题没有快速反应过来前缀和维护,并且后面的枚举部分可以用到调和级数的思想,所以没有做出来。
其实最后时间本来也不多了吧,H 做完也确实是没多久了。然后吃了迟来的亏。
下次加油!ヾ(◍°∇°◍)ノ゙

浙公网安备 33010602011771号