【2021~2022】模拟赛乱写 Period I

ZZH与计数

因为题目里面所涉及的操作和每个 (1) 的位置没有关系,只与数量有关,那么设 (f_{r,a,b,i,j}) 表示原先有 (a)(0)(b)(1),在进行 (r) 次操作之后有 (i)(0) 变成了 (1),同时有 (j)(1) 保持不变

转移是相对容易的:考虑这一次选择的操作对数字中 (0/1) 数量的影响

  • 选择用超集减少 (1) 的个数来转移,概率是 (p),方案如下:

    [sum_{x=i}^{a}sum_{y=j}^bf_{r-1,a,b,x,y}frac1{2^{x+y}}inom{a-i}{x-i}inom{b-j}{y-j} ]

  • 选择用子集增加 (1) 的个数来转移,概率是 (1-p),方案如下:

    [sum_{x=0}^isum_{y=0}^jf_{r-1,a,b,x,y}frac1{2^{n-x-y}}inom ixinom jy ]

直接枚举 (a+b=n) 的部分然后对 (r) 进行矩阵快速幂即可

这部分复杂度为 (n^7log m),但是注意到合法的 (i,j) 状态总和在 (frac{n^2}4) 左右,那么成功带了 (frac{1}{64}) 的常数,甚至更小

剩下的部分枚举 ((s,t)) 直接上式子复杂度是 (2^{2n}) 不能通过,那么考虑对这部分进行 ( m{DP})

(g_{i,S,a,b}) 表示当前考虑到了二进制下 (i) 位,当前得到一个数字 (S),但还需要让 (i) 为从 (0) 变成 (1),有 (j) 位从 (1) 变成 (0)

初态是

[g_{0,S,i,j}=v_S imes f_{m,C(S),i,C(S)-j} ]

其中 (C(S)) 表示 (S) 的二进制表示下 (1) 的个数

最后一维的含义是如果要最后有 (C(S)-j)(1) 被保留的话现在就需要有 (j)(1) 被删除,恰满足等式左侧的含义:需要有 (j)(1) 变成 (0)

这里并不需要让 (S)(t) 后面的二进制位下都满足是 (0),这个东西转移直接考虑修改当前二进制位的值即可

貌似需要调整 (g) 数组的维度顺序来减少取址用时

T4显然也是我整的

为了书写方便,以下将集合 (S) 中元素分配下标,(G) 表示集合 (S) 中元素的最小公倍数

观察到 (n)(maxlimits_{xin S} x) 大很多时,答案为 ( m{GCD_{xin S} x}),下证最大值上界为 (frac n2)

(forall xin S,xle m),不难根据 ( m{Exgcd}) 写出方程:(sumlimits a_iS_i=G),其中 (a_i) 是分配的系数,带标号

考虑一个包含 (a_i) 个有标号 (S_i) 的多重集,如果 (a_i>0),则多重集中有 (a_i)(S_i),反之包含 (-a_i)(-S_i),设位移 (v) 初始为 (1),每次可以向其加入一个多重集中的元素,需要保证 (vin [1,n])

  • (vle m)

    此时不一定存在一个 (S_i< v) 但是一定有一个 (S_ile m) 满足 (S_i+vle 2m)

    可以据此约束 (m) 的上界:(2mle n o mle frac n2)

  • (v>m)

    那么一定可以找到一个 (-S_i) 满足 (v+(-S_i)ge 1),因为如果没有负位移,根据方程 (sum a_iS_i=Gle m)

如果一个局面中 (S) 中元素均大于 (frac n2),那么存在一些点不能和任何点连边,设 (mn) 表示集合最小值,则这样子点的数量为 (2mn-n) 个,可以把它们直接加到答案中,并将长度及 (S) 中元素减去 (2mn-n),变成一个子问题,推导可以发现此时集合中存在小于等于半倍长度的元素

那么可以将此时所有 (le frac n2) 的元素取出并求出 ( m{gcd}) 设为 (d),剩下元素能作为合并集合的是那些 (d+S_ile n,S_ige frac n2) 的部分

这些元素能跨过并合并所有现存集合,可以直接 (dleftarrow gcd(d,S_i)),不难发现直接按照从小到大的顺序扫描所有 (S_i) 就能完成全部合法元素的合并,因为取 (gcd) 会让 (d) 不增

当前状态下最后没有被处理贡献的元素是 (S_i>frac n2,S_i+d>n),而且数量很少,可行边的左端点在 ([1,n-S_i] (n-S_i<d)) 中,此时可以保留 (d+n\%d) 长度的线段,即在同余意义下分组,并将这些未处理的 (S_ileftarrow S_i+nlen-n),此时变成原问题子问题,可以递归处理

注意 (d) 也要放到新集合中以防 ([i,i+d]) 这样的同余组被重复记

每个元素最多被降值 (log) 次,每次处理最多有 (Theta(1)) 个元素没有被降值,附加排序的复杂度,总复杂度 (Theta(mlog^2n)),常数小到跟乘 (frac1{log n}) 一样

游戏

由于每个长度 (K) 对应的总方案数是确定的,那么得到每个情况的方案数就能得到答案

考虑对于每个长度计算在 (A) 中选出子串 (X) 的字典序不大于 在 (B) 中选出的子串 (Y) 的方案数,再算出来 ( m{Ord(X)ge Ord(Y)}) 的方案数,两者求和减掉总方案即平局方案

不难发现要处理 (X=Y) 的情况这就是 (LCP),套路地使用 (SA):考虑对串(A* B) 构建后缀数组

对于每一个属于 (A) 的后缀,排在它后面的属于 (B) 的后缀和它产生的贡献是 (1sim min(len_A,len_B)) 长度的答案均 (+1)

如果进行后缀排序之后按照 (sa) 的顺序处理所有下标,并对每个长度维护权值,如果是 (B) 的后缀就让 (1sim len) 的权值增加 (1) 而遇到 (A) 中的后缀让权值加到对应长度的答案中去

对于在 (SA) 序上的逆序对,对不大于的贡献还可以是等于,这可以用 ( m{height}) 上类似的方式来维护

从前往后,在遇到 (B) 的后缀时,将 (1sim len_B) 的贡献 (+1),遇到每一个 (height) 都将大于 (height) 的贡献清零,遇到一个 (A) 的后缀 ,就将 (1-height_A) 的贡献加进对应长度的答案

这时候那么需要一种维护两个权值的数据结构,满足可以让其中之一加 (1),还可以让一个加到另一个上去和清空其中之一

使用行向量 ( m{[1,dlt,ans]}) 表示每个长度对应的信息,那么加一、清空,加到答案中去分别对应三个 (3 imes 3) 的矩阵,直接用线段树维护所有区间矩阵乘法即可

注意这里不可以标记永久化,因为矩阵乘法没有交换律

到这里不能通过,因为矩阵乘法复杂度高,但是观察发现第一行和最后一列只有两个 (1),而且在进行乘法的过程中这个性质一直满足,那么只需要维护右上角的 (2 imes2) 的部分即可

矩阵乘法复杂度降到了 (4),可以通过

石子游戏

每堆石子互相独立,局面是否满足先手必胜等价于 (xor_{i=1}^n SG_x(a_i)>0)

根据定义大力手玩可以得到 (SG_k(x)=x\% (k+1)),那么问题转化成了求一堆数模特定数的异或和

由于是取模运算,可以使用 (x\%y=x-lfloor frac{x}y floor imes y) 来进行第一步转化

又出现了熟悉的除法,那么明示调和级数,同时剩下的问题为统计 ([ky,(k+1)y)) 中的数在每一位下的贡献

先设 (cnt[l,r,j]) 表示 ([l,r]) 中的数字 (x) 满足 (x-l)(j+1) 个二进制位下为 (1) 的堆的数量

可以先对题目中给出的 (c_i) 求前缀和,同时预处理 (f_{i,j}) 表示满足 (x-i) 在第 (j+1) 个二进制位下有数的堆的数量

求解 (f) 非常容易:只用考虑 (i) 及其后面 (2^{j+1}) 个数中的状态,剩下的用 (f_{i+2^{j+1},j}) 统计

不难观察到对一个 (f_{i,j}) 贡献的一定是一段一段的 (c_i) 的和的形式

那么求一个 (cnt[l,r,j]) 只需要找到最后一个 (pos=l+k2^{j+1}le r) ,并将后面的数字删去,再使用前缀和把 ([pos+2^{j},r]) 中数字补回来就行了

本题可以大力剪枝:发现对于一个模数如果在一个二进制位下余数有贡献的数的数量是奇数,那么异或和必然不为 (0) ,后面的二进制也不用再找了

古老的序列问题

先分治,将询问挂到线段树节点上面:如果跨过节点中点则和朴素分治类似,完全覆盖者和线段树区间查询类似

考虑跨过区间中点 (mid) 的询问的回答,做法仍然是维护每个区间右侧点的历史答案和,在左端点处统计贡献

观察答案增量的表现形式:区间的最大值乘最小值,信息可能分布在 (mid) 的左右两侧,分类讨论

不难发现左边 (min) 函数单调递减,(max) 函数单调递增,使用左边 (min) 作为区间 (min) 的区间单调右移,(max) 同理,可以用两个单调指针得到

剩下的就是线段树维护了,需要写出 (4) 个懒标记,不过互相独立,只是稍微打打字而已

为什么有老哥能会 (Theta(nlog n)) 高论呀?

记忆碎片

观察最小生成树的 “生成” 过程:中间态可以表现为一些大小和为 (n) 的联通块

如果忽略联通块上点的标号,状态可以表示成一个 (n) 的划分

本题中 (n) 的数量级比较小,可以直接 (dp[i][S]) 表示加入了 (n^2) 条边中的 (i) 条之后状态成 (S) 的方案数

那么转移简单得离谱:

  • 如果当前边不在最小生成树上那么只能在联通块里面补边,这里需要统计每个状态中联通块连满能用多少边

  • 在最小生成树上的边需要合并联通块,暴力枚举状态里面的就行

复杂度是 (Theta((n^2)P(n))) 的,可以通过

置换

首先发现

[f(P)= m{LCM}_ {Rin P} Len(R) ]

其中 (R) 表示置换环,(Len(R)) 表示 (R) 置换环的长度

还是写出答案的直接表达式:

[sum_{sum x_i=n}frac{n!}{prod x_i!}prod (x_i-1)! frac{1}{prod y_i!} ]

这里 (y_i) 表示 (x_k=i)(k) 的数量,式子最开始是多重集排列,中间是不同长度置换环数量,最后去除重复

直接冲整数划分复杂度甚至跑不动 (n=100),只好写出 ( m{DP}) 式子:(f_{i,j}) 表示选出的数字和为 (i)( m{LCM=j}) 的方案数

所有可能作为最小公倍数在满数据范围内有八十来万,考虑分质因子中是否含有 (>sqrt n) 来处理:

如果只计算质因子不超过 (sqrt n) 的数字的最小公倍数只有两千来种,数量级可以接受,那么将 (>sqrt n) 的数字作为方案数存下来

注意到每个不超过 (n) 的数包含的 (sqrt n) 的质因子个数和次数均不超过一

对于质因子小那些还是执行上面的算法,存在大质因子的数,作为置换环长加入时将大质因子 (P) 乘当前的方案数加入原方案数即可

B关系

稍微花时间编一个(假的)(Theta(n^3))( m{DP}) 可以发现 (n) 需要矩阵快速幂,而 (R) 是作为矩阵中的系数来求解

优化是一种叫做 ( m{DP})( m{DP})( m{trick})

题目中要求 ( m{LCS}) 要不小于序列长度减 (2),回看朴素的 ( m{LCS}) 转移,存储两维差大于 (2) 的状态对最终答案求解无意义

那么计算 (f_{n+1,n+1}) 只需要 (f_{x,y}[exists x,y=n][forall x,yge n-2]) 的值和 (A[n-1],A[n],B[n-1],B[n]) 四对的相等关系

实现的时候存 ( m{DP}) 值用类似 (n-f_{n,n}) 的方式进行存储值,然后把这些需要求的 放到结构体里面做就行

对于相等关系将序列里面的四个值随便赋一些 (le 4) 的值放起来,注意要满足最小值是 (1) 且值域连续

那么先给 (A[1],A[2],B[1],B[2]) 随便赋值搜出来所有 (nle 2) 的合法状态,每个状态可能的方案数是 (inom R {num}),其中 (num) 表示四个的里面最大颜色

对于状态之间的转移建立基矩阵,两个元素之间的转移不是一对一对枚举,而是实地枚举 (A[i+1],B[i+1]) 的值,注意这两个量可以枚举到 (num+1,num+2)

同上,还是不关注具体是谁,还是只关注相等关系,转移方案数如下:

  • (A[i+1],B[i+1]le num) 颜色固定,系数为 (1)

  • 二者其一大于 (num),或者两者都大于 (num) 且颜色相同,选择方式只能是在 (R-num) 中选一个

  • 都大于 (num) 且不同,那么是 (inom{R-num}2)

注意颜色的离散,每个状态里面的颜色 标号 不能大于 (4),而离散化方式非常离谱,不同的方式导致状态数量差异巨大,按照 (A[0],B[0],A[1],B[1]) 的顺序用逐次加入 std:map 可以做到 (200) 左右的数量级

实现两个状态对应的结构体转移是容易的,使用朴素 ( m{DP}) 的转移式子完成即可,注意如果被转移者 (f_{n,n}ge3) 则新的状态无意义

另注意状态可能不止搜出来的那些,会动态添加一些

最后写一个矩阵快速幂即可

黑白

又一次学习 ( m{SG}) 函数

预处理 (f_{o,z,s}) 表示有 (o)(1)(z)(0) 的序列中 ( m{SG}=s) 的方案数,那么计算概率,总方案是 (inom{o+z}z)

转移考虑枚举添加 (xin[0,100-z])(0) 和一个 (1),手动模拟序列 ( m{SG}) 值就知道是转移给 (f_{o+1,z+x,x+(sle x)})

具体而言,每个非末尾 (1)( m{SG}) 值必然是 (0),其余点的 ( m{SG}) 值的后继为拿掉能拿掉的数字后能走到的点的 ( m{mex})

之后做一个 (g_{i,j}) 表示到第 (i) 个序列,异或和为 (j) 的概率,转移是 ( m{FWT}) 状物 的 ( m{DP}) 就行了

不难想到对模数进行根号分治:

  • 对于模数不大于 (sqrt n) 的部分,枚举每个模数和余数

    将询问点,修改点的深度对模数取模,分开每个 ( exttt{(模数,余数)}) 处理,这样进行子树区间加法并不会对其它询问产生影响

    每个询问对每个模数都要查,那么有 (qsqrt{n}) 次查询,每个修改的模数余数固定,那么只有 (q) 次修改

    使用一个 单点查询,区间修改 的分块即得到 (Theta(qsqrt n)) 的复杂度

  • 对于模数大于 (sqrt n) 的部分,求出每个修改对哪些深度有影响

    枚举深度统计答案,修改拆成了 (qsqrt n) 次,每个询问有特定深度,那么要进行 (q) 次查询

    这时候可以使用一个 区间查询,单点修改 的分块进行子树加法,复杂度 (Theta(qsqrt n))

本题使用根号分治后巧妙使用根号平衡优化了复杂度,值得一想

万猪拱塔

考虑判断一些格点能否构成一个矩形的方式:

将矩阵扩展成 ((0,0) o (n+1,m+1)) ,每个 (2 imes 2) 的小矩形的起始点为 ((0,0) o (n,m))

将选定格点染成黑色后,如果这些小矩形中黑色点个数为 (3) 的格子数量为 (4) 且不存在黑色格点为 (1) 的小正方形则构成一个矩形区域

正确性是显然的

用线段树维护 (f(l,r)) 表示区间中的点染成黑色后满足格子里面点数为奇数的格子数

不难发现加入一个点后,黑色格点奇偶性变化的格子只有相邻四个,分开处理变化,即对于每个小矩形分段修改贡献

抑郁刀法

不难发现原图中 (num) 个一度点对答案的贡献是乘 ((k-1)^{num}),那么可以把这些点缩起来

剩余的二度点 (x) 连向 (a,b),删去其后给 (a,b) 连一个新边,如果 (a,b) 同色,(x)(k-1) 种选择,而 (a,b) 异色有 (k-2) 种选择

(f(a,b)) 表示 (a,b) 同色的附加贡献,(g(a,b)) 表示异色,初始化 (f(a,b)=0,g(a,b)=1)

如果合并两个带权边则考虑实际含义即可转移((f=f_1f_2+(k-1)g_1g_2,g=g_1f_2+g_2f_1+(k-2)f_1f_2)

照着转移可以把 (2) 度点删掉,剩下的三度点 (nle 10,mle 15) 可以使用 (DP) 维护

转移考虑添加一个集合表示集合里面的点选择同一个颜色,需要添加一维状态表示选的颜色数,最后需要乘组合数

实现起来细节庞杂,其一是重边不是合并来的,而是乘起来的

seat

每个人对应的最大长度长度是一定的,同时经过若干人后剩余线段的可重集是一定的

由此不难发现一个最大长度对应的人是一个区间

每个长度为 (n) 线段每次会被分成 (lfloorfrac{n}2 floor,lceilfrac n2 ceil) 两个,那么我们发现不同的最大长度只有 (Theta(log n)) 种:(lfloor frac{n}{2^k} floor,lceilfrac n{2^k} ceil)

下文把这样的每个最大长度对应的连续区间成为一个段

注意到对于长度为偶数的区间和长度为奇数的区间并不等价,所以要求出每个段中偶数长度区间个数

考虑对一个特定的最大长度求出每个位置的概率,设 (dp_{i,j}) 表示取出 (i) 个区间,剩余 (j) 个长度为偶数的区间

转移考虑有剩余哪些转移点来计算当前选奇数/偶数的概率,这个 ( m{DP}) 是问题的关键

最后需要将偶数区间带来的概率进行平均,因为前面对区间长度有影响,但是对选择位置是等概率的

实现的时候用优先队列维护可重集合来求每个最大长度对应多少个小 ( m{G}),不难发现偶数长度区间会被先取出,所以计算偶数长度时会稍方便

回文串

首先有"本质不同的回文串的数量级是 (O(n)) 的"

证明很简单,考虑sam上最多有 (2n-1) 个节点,同时这些节点中每个最多有一个回文串

(如果有多个的话,那么短串的 (endpos) 比长串要多)

其实在这个题目里面关注的是 (midpos),那么给所有的回文串标号

(manacher) 处理所有的回文中心,把短串向长串连边得到一个树

对于每次处理的 (id[i-r[i]+1,i+r[i]-1]) 异或上 (i) 最后按照 (SAM) 维护 (endpos) 个数那样维护 (midpos) 的异或和即可

复杂度 (Theta(n))

整除

先把 (x=1) 的判掉,注意这里应该是系数和是 (m) 的倍数

使用等比数列求和公式把原多项式乘上 (x-1),然后使用多项式取模把原多项式次数降到 (m) 以下,设此时 (R(x)=sum a_i x^i)

关于多项式取模的部分,对于每个 (a_ix^i),给 (x^{i\%m}) 贡献 (a_i) 的系数

此时如果余多项式为 (0) 则有无穷解,反之解不会大于 (max{a_i})

那么题目转化为带入一个 (x) 判断多项式模 (x^m-1) 是不是满足系数均为 (0,-x+1,x-1)

后面两个系数的取值可以使用等比数列求和得到一个倍数的形式

使用 (set) 找到当前所有大于等于 (x) 的系数,按照高精度数计算的思想进行 "进位" 即可

考虑到 (sum a_i)(O(n)),不断减得到一个调和级数的复杂度,套上 (set),那么总复杂度 (Theta(nlog^2n))

词典

考虑到这个模式很像一个 (trie) 树删儿子的模型,那么设计一个 (f_i,g_i) 表示左/右子树选 (i) 个的最小代价,转移想想就有了

考试的时候看着 (O(n)) 的部分分就打了个表发现转移点最多差 (1),卡了卡空间得到了 (50)

大力打表发现 (f(i)-f(i-1)) 单调不增而且都非常小,那么盲猜可以预处理每个 (x)(f(n)-f(n-1)=x) 最大的 (n),查询时二分

  • (f(n)) 是凸函数:使用右下凸包和右下凸包的闵可夫斯基和就是 (min-add) 卷积

  • (f(n)-f(n-1))(log^2n) 级别的数,这个貌似用二叉树对应深度上的点就能证明

那么可以倍增套二分得到 (x) 的界点,注意实现的时候需要 (1.5) 倍倍增,三分 (f(i)) 的转移点的时候把下界设成 (frac i3)

做法貌似神乎其神,其实是一点没懂……学到了 (1.5) 倍倍增来卡常?

未来拼图

不难发现是个循环卷积,那么直接想就知道是多项式开根

那么 ( m{FFT}) 已经是循环卷积了,所以直接 ( m{DFT}) 之后点值开根再 ( m{IDFT}) 回来是正确的

直接给复数开根会得到两个结果,硬上枚举是 (2^n) 的,并不能通过

但是发现 (P_i=P_{n-i}),这样子只要枚举一半的根的选择,对称的部分跟着选

注意到这里 (n=25) 并不是 (2) 的整次幂,同时它也很小,那么直接 (Theta(n^2)) 带入 (omega_n^i) 进行点值计算和插值还原

实现注意以下:

  • 复数开根结果可能相同,所以得到的多项式要去重

  • (n^2) 卷积得到结果来判定合法

  • 注意 (P_i) 是非负整数,( m{IDFT}) 得到负值的时候要舍去

  • 注意 (P_i=P_{n-i}),所以枚举一半这里势必有细节

最大价值

看看这个部分分设置想到了大力 ( m{EK}) 和模拟费用流,都和正解没有关系但是启发是不是代价有凸性

写了个暴力发现还真能满足 (k) 大小的集合 是 (k+1) 大小的集合的子集,那一看就是一个 ( m{Insertion}) 的东西

结果做了一场也没看出来咋维护,愣没看出来整差分表

问题写成 ( m{DP}) 就是 ( m{f_{i,j}=max{f_{i-1,j},f_{i-1,j-1}+a_i imes (j-1)+b_i}})

如上所说,如果在某个位置 (k) 加入一个元素,其对差分表的影响是后缀加 (a_i),对应点加 (a_i(k-1)+b_i),前缀不变

按照上述定义写出对应的转移方程不难得到

那么按照 (a_i) 从小到大排序加入平衡树即可

大水题

先对序列求前缀和

如果直接给定一个区间,判断若干种牛出现次数出现次数相同的方式是取出这些种类的点值差分,如果差分表对应那全相同则出现次数相同

这种做法正确性不难自证,但直接应用到本题中,即使用 ( m{hash}) 表维护状态对应做端点 时间复杂度达到了 (Theta( m{maxb 2^{ m{maxb}}n}))

真的需要对所有的 (2^{ m{maxb}}) 种 种类搭配方式都枚举一次吗?

对于一个固定区间右端点,在左端点从右往左挪的过程中,牛出现的种类数只会变化 ( m{maxb})

那么对于枚举的右端点,动态维护每个左端点到当前右端点的牛的出现集合

不难发现每次只需要修改 ([ m{lst[a[i]],i-1}]) 中的点作为左端点时的出现牛的状态集合,伴随状态集合的变化,对应的差分表也会增加数字

这部分会遍历 ( m{maxb}) 次数组,复杂度比较优秀

那么在 unordered_map 中把不合法的状态左端点改成 (-1),把当前的牛的集合加入即可

更新答案考虑按照上一次出现的位置增加进入状态再去哈希表里面查即可

这样的话复杂度是 (Theta( m{maxb^2n})) 不可避免地带了 (8) 的常数,但是比 (256) 好多了

佛罗里达

面向范围编程可以发现正解复杂度在 (Theta(n^3)) 左右,那么直观的想法就是枚举所有边作为一个集合的最大边

不妨设 (max(A)le max(B)),那么枚举 (B) 之后答案必然有单调性,

那么先二分 (A) 的权值,然后判断是否可行是一个明显的 ( m{2-sat})

  • 对于那些 (vle max(A)) 的边没有限制

  • 对于那些 (max(A)<vle max(B)) 的边不能都在集合 (A) 中所以分别连向对方的逆命题即可

  • 对于 (v>max(B)) 的情况,那么除了上面的边以外,逆命题连反向边

至此得到了 (Theta(n^4log n)) 的做法,基本功扎实的话可以一两分钟想到

和上一题一样,请问:真的有必要枚举所有边作为 (max(B)) 吗?

考虑对完全图求一个最大生成树,黑白染色后,如果 (B) 集合包含两种颜色的点,那么集合最大边一定在最大生成树上面

首先 (B) 集合包含的点在生成树上距离不能都超过二,否则 (max(A)>max(B))

如果距离都等于二那么都是同一个颜色

至此证明了如果集合包含两种颜色的点,那么 (max(B)) 一定在最大生成树上

这样子只需要枚举 (O(n)) 级别的边就能覆盖这部分,剩下的是在染色之后黑色点一个集合,白色一个,分别枚举即可

原文地址:https://www.cnblogs.com/yspm/p/15205840.html