20260706紫黑训练
P3244 [HNOI2015] 落忆枫音
before
选出一颗树并不好做,正难则反,考虑删边。
假如没有环,删至每个点入度为 1 即可,方案数为每个点入度的乘积。
把加完边后的图里的环找出来,强制通过删边的方式让图中无环。
假如是串联的环,彼此独立处理,把环内所有可能乘积之和算出来。
并联的环要一起做,可以各自把支路一条边删了,也可删干路一条边。同样把所有可能乘积的和算出来。
再把所有串联环或并联部分的结果相乘,再乘以非环部分入度,即为答案。时间复杂度为 \(O(n)\)
after
赛时思路过于复杂。实际上观察到如果加边后仍然按照入度的乘积方法计算图中最多只会出现一个环的性质后,采用总方案除以每个环上点入读之积,再把它们求和,再用总方案数减去即可。
P4051 [JSOI2007]
before
问题即为求以所有 \(n\) 个位置为开头的字符串的字典序排序,然后根据这个顺序把开头位置 -1 的位置就是最后一个。
如果直接暴力做可能会遇到两个位置前面很多位都相同,这样算法时间复杂度上限会到达 \(O(n^3)\)。考虑优化比大小部分。
先把开头位置进行分组,一样的放一组。假设两个开头位置前 \(i\) 位相同,由于是比较字符串字典序大小,所以只用看 \(i+1\) 位往后,所以可以想到突破点在于充分利用已知信息。
由于已经进行分组,所以可以把这个两个开头位置后的第 \(i\) 位一起提出来,它们必然在同一个组内。然后可以用 ST 表的处理思想,按层次倍增解决。首先是把每一组按长度为 \(len=2\) 的字符串进行初步排序,随后进入 \(len=2 \times 2-1\) 的层次,把初步排序无发区分大小(如 acb,acd)的再用以 c 开头的 \(len=2\) 的信息解决 \(( cb<cd )\) 。大概 \(log_2 n\) 次解决。每一次还需要再次排序,因此总的时间复杂度上限为 \(O(n log^2 n)\) ,但远远达不到,应是接近 \(O(n log n)\) ,可以通过。
after
C++ std::sort 要求比较函数 cmp(x,y) 必须满足:
1.cmp(a,a) 一定返回 false
2.若 cmp(a,b)=true,则 cmp(b,a)=false
3.传递性等规则
依旧有点复杂,可以直接改 sort 比较函数,用哈希和二分即可。
P3179 [HAOI2015]
before
题意即一开始选四个人,会有一个人胜利,把胜利的人置于队头,剩下的按照原来顺序放至队尾,循环下去。
如果我们关注点只在第 k 个人上,那么其他人对于我们来讲没有区别。
所以关键点在于 k 前面有多少个人。
可以考虑对于每个可能人数求概率。
k 每次前面都会少三个人,所以模三后实际上只有f[1],f[2],f[3]三种可能。
after
完全想不到可以用高斯消元解决问题,DP状态也没想到。积累trick。

浙公网安备 33010602011771号