Codeforces Round #809 (Div. 2)
作者:互联网
VP的。
这场 C 是真的恶心,还好一发过了要不然罚时就更起飞了。
D2
考虑枚举 \([l,r]\),判断能否使得所有 \(\lfloor\frac{a_i}{p_i}\rfloor\) 都在 \([l, r]\) 范围内。
对于每个 \(a_i,\lfloor\frac{a_i}{p_i}\rfloor\) 只有 \(\sqrt{n}\) 种值,所以这个判断可以用一个桶实现。
注意每个 \(r\) 能取得的最大 \(l\) 随着 \(r\) 的增加单调不降。可以 two-pointers。
然而空限 64MB。卡不过去,怎么办?
其实方法很简单,不要把每个 \(a_i\) 的所有 \(\lfloor\frac{a_i}{p_i}\) 一下子全部扔进一个序列里。假设从大到小枚举 \(r\),当目前的 \(\lfloor\frac{a_i}{p_i}\rfloor>r\) 时,再把下一个更小的 \(\lfloor\frac{a_i}{p_i}\rfloor>r\) 纳入考虑范畴。
vp 的时候没写 D1,直接写的 D2,由于 vector 内存释放问题改成了前向星,改了半天,赛后 30s AC,蚌。
然后经高手指点才知道 vec = vector<int>()
就可以释放内存,更蚌埠了。
无知的后果。
E
赛后补的。
我的思路是这样的:依次加入每条边,并查集启发式合并。每个集合的根节点存下当前集合内点构成的所有区间。合并时二分,如果 \([l,k]\) 与 \([k+1,r]\) 合并到了一起那么 \([l,r]\) 内的区间的答案就不超过当前边的编号。这个可以线段树维护二维数点(min 不能树状数组),或者更优美的,注意到每次产生的 \([l,r]\) 必然不相交或者完全包含,把它建成一个树形结构,对于每次询问 \(x,y\),求 \(x\) 与 \(y\) 的 lca 就是答案。复杂度 \(O(n\log^2 n)\)。
官方题解说,\([l,r]\) 连通等价于对于 \(l\le i<r\),\(i\) 与 \(i+1\) 连通,所以我们记 \(f(i)\) 表示最少加入第几条边时 \(i,i+1\) 连通,查询等价于一个 rmq。然后这个 \(f(i)\) 非常好求,可以并查集启发式合并,还可以将第 \(i\) 条边权值设为 \(i\) 跑最小生成树,\(i\) 到 \(i+1\) 路径上的最大边权就是 max。复杂度 \(O(n\log n)\)。
这个生成树的奇妙结论怎么证呢,如果要从生成树的角度来证明很难证,但是如果从 kruskal 的过程考虑你会发现这不就是并查集合并的过程吗。。。
对比一下简洁程度,代码长度和复杂度,高下立判,技不如人,赛时写不完也只能甘拜下风。更何况我因为 vector 内存释放卡在了D2
这个 \([l,r]\) 连通转为 \(i\) 与 \(i+1\) 连通是个没见过的 trick,学到了。其实这个 trick 也不局限于连通。
标签:lfloor,连通,frac,Codeforces,rfloor,809,vector,Div,D2 来源: https://www.cnblogs.com/stinger/p/16574042.html