csp-s模拟8
T1 score and rank
特殊性质,题意转换
妙妙题
对于 \(S\) 小于等于 \(0\) 的情况答案显然是所有大于等于 \(S\) 的个数。
现在讨论 \(S\) 大于 \(0\) 的情况。
先对序列做一个前缀和,题目要求即是让所有值减去前缀最小值小于 \(S\)
考虑有一段连续正整数的和大于 \(S\),则贪心的从大到小删除序列中的值,直到和小于 \(S\)。
考虑有两段连续正整数中间夹着一段负数并且两段正整数的和都大于 \(S\) 而且这三段的和都大于 \(S\),依旧是考虑贪心删除,但需要考虑顺序,先对两段正整数段内贪心,若此时整段的和依旧大于 \(S\) 再合并贪心。
发现这种做法是可扩展的,但是时间复杂太高了。
观察题目性质发现对于一段正数后连着一段负数,记这两段的和分别为 \(S1,S2\),且 \(S1+S2>0\),那么对于前缀和而言删去那段正数中的数最多能对其后的值减少 \(S1+S2\) 的贡献,即就是说当删除的和大于 \(S1+S2\) 时就对这个题而言没有贡献了。对于上面的做法启发我们维护这个正整数段的前 \(k\) 大,且这前 k 大的和恰好大于 \(S1+S2\)。对于前者很好用堆去维护,后者该怎么维护呢?考虑用正数去填充负数,意思是说对于正整数断后的负数每添加进来一个就用正整数段中最小的正数去填充它直到为正然后再入堆,显然最后的值一定依旧是最小的,堆中的和恰好为 \(S1+S2\),对于本题的答案并不关心值而是关心个数,所以这样做是对的。如果堆中值的和不足以填充这个负数,则直接清空堆等同于连续段的左端点不可能在其左边。
每个数只会进出堆一次,所以时间复杂度为 \(O(nlogn)\)。
T2 HZOI大作战
签到题
由于数据较大,有点卡常卡空间。
离线下来对树上的点和询问向祖父中第一个大于自己的点连边,可以考虑倍增 \(max\) ,然后根据 \(dep\) 直接倍增跳就可以了。
时间复杂度 \(O(nlogn)\)
T3 Delov的旅行
二分,DP优化
题目的一些限制使得每个点只能进出子树各一次且最后回到根。
答案显然具有单调性,二分答案。
考虑怎么检查二分值是否合法,首先有个 naive 想法,设计状态 \(f_{i,x,y}\) 表示点 \(i\) 中最早遍历到的叶子节点到 \(i\) 的距离为 \(x\),最晚遍历到的叶子节点到 \(i\) 的距离为 \(y\) 是否合法,转移考虑背包即可,但是值域过大复杂度直接就炸了。但是发现每个叶子到个点的距离是固定的,所以会产生很多冗余的状态,那么就可以将所有的状态放到 \(vector\) 中就行了,但是此时依旧有冗余状态即对于 \(x_i≤x_j,y_i≤y_j\) 对于状态 \(j\) 而言显然是不如 \(i\),所以只需要维护一个 \(x\) 单调递增 \(y\) 严格单调递减的状态即可,排序去重,上双指针即可。注意左右儿子的顺序未定,且儿子本身也是可以翻转的,所以可以将状态两维 \(swap\) 一下再放入。
分析时间复杂度,每个点的状态数为它一个儿子的二倍,即每层有 \(O(n)\) 个状态,有 \(O(logn)\) 层,所以总时间复杂度为 \(O(nlognlogV)\)。
T4 gtm和joke的星球
斯坦纳树
模板题
首先答案的形态一定构成一颗树,因为若存在环,则可以删去一条环上的边使答案减少。
因为关键点的个数很少( \(k≤10\) ),所以可以考虑状压 + 树形 \(DP\) 去解决。设计状态 \(f_{i,s}\) 表示当以 i 这个点为根,且子树内具有的关键点包含 s 这个集合的最小答案,那么转移可以考虑集合合并以及根的转移。
集合合并 \(f_{i,s}=\min\{f_{i,s1}+f_{i,s2}\}(s1∪s2=s)\)
根的转移 \(f_{i,s}=\min\{w_{i,j}+f_{j,s}\}\)
对于第一种直接枚举子集转移就行了,第二种可以考虑在第一种整体转移完后(即这个集合对应的所有根都转移完后),进行最短路松弛即可。
分析时间复杂度,对于第一种转移,由于是枚举子集所以时间复杂度为子集的个数为 \(O(3^k)\)。对于第二种转移,每种集合都会进行一次最短路进行松弛,若使用 Dijkstra 则为 \(O(2^k(n+m)logm)\)。总时间复杂度为 \(O(3^k+2^k(n+m)logm)\)。