Codeforces Round #775 (Div. 1, based on Moscow Open Olympiad in Informatics)(CF1648)
A
签到题,略。
B
Description
给定一个长度为\(n\)的序列,要求判断是否满足\(\forall x,y\in \{a_i\}, x>y\),有\(\lfloor x/y\rfloor \in \{a_i\}\)。
\(\sum n \le 10^6, c = \max \{a_i\}\le 10^6\)
Solution
对于序列中的每个数\(y\),枚举\(z\),找到区间\([x_l,x_r]\)满足\(\forall x\in [x_l,x_r]\)有\(\lfloor x/y\rfloor = z\),如果\(\exist a_i \in [x_l,x_r]\)且序列中没有\(z\),则不满足要求。
枚举每个数倍数的时间复杂度是\(O(c\log c)\)的。
C
Description
给定两个数组\(s,t\),对\(s\)进行排列,要求\(s\)字典序小于\(t\),问排列方案数。
\(|s|,|t|\le 2\times 10^5\),\(s_i,t_i \le 2\times 10^5\)
Solution
对于\(s\)的每个位置\(i\),将\(s_1\dots s_{i-1}\)依照\(t\)填满,第\(i\)位填一个比\(t_i\)小的数,后面的就可以乱填了。
若\(s_i\dots s_n\)剩下可以填的数里不同的数的出现次数为\(a_{x_1}, a_{x_2}, a_{x_3}, \dots\),假设第\(i\)位填入\(x_1\),那么方案数为
那么所有小于\(t_i\)的\(x_i\)填入\(s_i\)位置的方案数为
维护乘号前面的分母,再用树状数组处理乘号后面的部分即可。
D
Description
有一个\(3\times n\)的方格,要从\((1,1)\)走到\((3,n)\),每次只能向坐标增加的方向移动一单位。每个格子有一个分数\(a_{i,j}\)(可能为负),走到该格子即得到这个分数。
第二行的格子一开始都是禁止通行的,有\(q\)条信息\((l_i,r_i,k_i)\)(\(k_i>0\)),表示你可以让自己的分数减去\(k_i\)使得第二行的\((l_i,r_i)\)允许通行。要求最大化最终分数。
\(n,q \le 500000\)
Solution
设\(a_{i,j}\)在第二维上的前缀和是\(s_{i,j}\),我们需要找到连续的一段\([l,r]\),用一些区间去完全覆盖它,分数即为:
我们对于每个区间找到区间内\((s_{1,i}-s_{2,i-1})\)最大的那个\(i\)作为左端点\(l\),然后以DP的形式往后面接区间,即对于每个区间的右端点,将区间\([l\color{red}{-1},r-1]\)内的右端点的信息选一个最大的转移过来,这个过程可以用线段树实现。
于是我们得到了对于每一个区间右端点,往前选取一个左端点的最大分数\(f_i\),并设\(s_{2,r}-s_{3,r-1}=g_r\)。
对于每一个区间\([l,r]\),找到\(i,j\)满足\(l \le i \le j \le r\),\(i\)为上一个区间的右端点,\(j\)为整个第二行通行区域的右端,故取\(f_i+g_j+k_{l,r}\)作为分数。
为什么不能直接对于每个区间找到区间内最大的\(g_i\)加到\(f\)上:不能保证右端点\(i\)一定在之前取的左端点的右边。
注意只开通一个区间的情况需要另外算。
E
Description
给定一张无向带权联通图\(G = (V, E)\),一条路径的通行费用为路径上的最大边权。
构造\(G\)的补图\(G'\)(数据保证\(G'\)联通),边\((u,v)\)的边权为\(G\)中路径\((u,v)\)的最小费用。
构造\(G'\)的补图\(G''\),边\((u,v)\)的边权为\(G'\)中路径\((u,v)\)的最小费用。
求\(G''\)每条边的边权。(\(n,m\le 200000\))
Solution
“路径上的最大边权”\(\Rightarrow\)最小生成树
\(G'\)的边数太多,我们考虑先求\(G'\)的MST,然后求\(G''\)的MST,最后在\(G''\)的MST上查询每个点对的费用即为答案。
以下是
Neal_lee
的解释orz:你先求出原图建重构树叶子的dfs序,那么边 (u,v) 在补图 mst 上的必要条件是:degree(u) + degree(v) >= abs(rank(u) - rank(v)) - 1
rank(u) 是点 u 在 dfs 序列上的位置
如此条件不满足,则在 rank(u) 到 rank(v) 之间必然存在一个点,和 u,v 都有连边,而 u,v 向这个点连边是更优的。
所以有 2max(degree(u), degree(v)) >= abs(rank(u) - rank(v) - 1),于是可以枚举 degree 较大的点(不妨是 u),rank(v) 在区间 [rank(u) - 2degree(u) - 1, rank(u) + 2degree(u) + 1] 中,可以发现可行的点对数量是 O(m) 级别的。
pre 和 nxt 是 dfs 序的链表,可以发现对于前面的 u,要两边都完整的枚举才不会漏,可能会有重复,但是根据 kruskal 显然不会影响结果。