题目链接:https://codeforces.com/contest/1795/problem/G
首先,考虑什么是合法的序列.排列中的第1个数,必定初始度数等于其本身度数,我们可以找到所有符合该条件的数,则这几个数之间绝对不会连边(因为连边则不存在合法序列).所以这些数可以随意排列其位置,我们将这些数去掉之后,再根据上述步骤直至所有节点去掉.
可以发现,我们可以根据上述步骤将数分成若干组,每个组内数字的顺序可以随意互换,但要注意组之间也可以形成答案,比如样例3中,5与1连边,度数为1,目标度数为0,则5可以在3之前或者3之后.
显然,每个数字消去前,在其之前要消去的数字,是一个固定的集合A,在其之后要消去的数字,也是一个固定的集合B,显然,集合AB之间,A与该数字,B与该数字之间都无法对答案作贡献.
将无向图转换,我们将设集合A中的点为u,该数字为v,我们将(u,v)这条无向边变成从u到v的有向边,设集合B中的点为w,则将(v,w)这条无向边变成从v到w的有向边,则上述中的定序关系可以按照边的方向传递,一条从u到v的边,表示u必须在v之前出现.则我们的答案就是该有向图不能相互到达的点(若可以相互到达,则代表定序),而该有向图存在一个拓扑序(若存在环则不存在合法序列),拓扑序在求有向图的时候即可顺便求出.
故我们先求出该有向图的所有边(按照上述步骤进行一个类似拓扑排序即可),然后统计能互相到达的点对数,显然,有向无环图求互相到达点对数是比较典的按照拓扑序的逆序进行bitset并.
然而,如果直接使用bitset会导致O(N^2)的空间复杂度,O(N^2/64)的时间复杂度.其中时间复杂度勉强能过,空间复杂度无法忍受.
划重点:有一个类似分块的trick,因为bitset的时间复杂度和bitset的大小成线性,我们可以缩小bitset的大小而不影响时间复杂度.如开N个大小为64的bitset,我们每次以64为一组,遍历1~N,每次只统计能到达该组的点的节点个数,最外层循环时间复杂度为O(N/64),内层每轮重置bitset复杂度为O(N/64*N),bitset并的复杂度为O(N/64*M);其中M为边的总数,统计节点个数的复杂度为O(N/64*N),最终时间复杂度仍为O(N^2/64),但空间复杂度已为O(64*N)
1 |
|