历年各赛事真题选做(一)

历年各赛事真题选做(一)

By DaiRuiChen007

推荐阅读:

  • A. [九省联考 2018] 秘密袭击
  • E. [HNOI/AHOI2018] 寻宝游戏
  • K. [APIO2020] 有趣的旅途
  • Q. [WC2018] 州区划分
  • V. [HNOI/AHOI2018] 排列
  • Z. [省选联考 2021 A 卷] 矩阵游戏

A. [九省联考 2018] 秘密袭击

Problem Link

I. 朴素的 dp

首先,我们知道答案就是求所有联通块中的第 k 大值和

第一步转化,我们可以拆分贡献,对于每个 i 求出:连通块中第 k 大数为 i 的方案数,把方案数乘以 i 再求和即可

第二步转化,我们可以把乘以 i 的贡献拆成 i 次计算的贡献,即:对所有 i,统计连通块中的 k 大数 i 的方案数,这样每个 i 恰好被计算 i

第三步转化,我们可以把“第 k 大数 i”转化成“值 i 的数 k 个”的条件,即:对于所有 i,求出 i 的数在连通块中出现次数 k 的方案数

在转化之后,我们可以设计一个显然的 dp 来解决这个问题,用 fu,i,j 表示以 u 为根的子树中值 i 的数出现恰好 j 次的连通块数量

为了防止算重,我们可以强制要求 fu,i,j 中统计的连通块一定包含 u,从而防止重复计算

fu,i,j 的转移比较显然,直接从对于每个 u 的儿子 v,用 fv,i,j 以一个卷积的形式往上转移

为了更加方便统计答案,我们不妨再定义一个 gu,i,j 表示所有 u 的子树中的 vfv,i,j 的和,即非强制选定 u 时的方案数,g 的转移比较简单,直接从 u 的所有儿子处转移 g 值并且转移 u 本身的 f

那么,答案就是 i=1nj=kngroot,i,j,即对于每个 i[1,n],统计选择值 i 的节点,选择了 kn 次的方案数再累加求和

II. 多项式技巧维护 dp

注意到 f 的转移很像对 j 一维卷积的形式,因此我们可以在 fu,i,gu,i 中用生成函数维护所有 fu,i,j,gu,i,j 的值

不妨假设 Fu,i=j=0nfu,i,j×xj,Gu,i=j=0ngu,i,j×xj

那么我们就把状态转移方程转化为如下的形式:

Fu,i=x[dui]vson(u)(Fv,i+1)Gu,i=Fu,i+vson(u)Gv,i

那么在这一步之后,我们把答案转化成了 i=1nGroot,ikn 次项系数的和

不妨假设 H(x)=i=1nGroot,i,那么原问题只需要我们求出 H(x) 即可解决

注意到在树上多次进行多项式乘法的复杂度较高,难以接受,因此我们考虑用用拉格朗日插值法把多项式乘法转化成普通的乘法

即,对于每个 x0=1,2,3,,n+1,我们把 x=x0 带入所有 Fu,i,Gu,i 的表达式,求出所有 Fu,i,Gu,ix=x0 处的点值,从而得到 H(x)x=x0 处的点值

最终,我们通过 H(1)H(n+1) 的点值运用拉格朗日插值法得到 H(x) 的系数表达,再把 kn 次项的系数统计到答案中

因此,我们只需要对于每个 x0,维护如下的转移:

Fu,i=x0[dui]vson(u)(Fv,i+1)Gu,i=Fu,i+vson(u)Gv,i

注意,此处转移方程式中的 Fu,i,Gu,i 都是数值而非多项式

III. 线段树加速转移

注意到在状态转移方程中,每个 i 对答案的实际影响很小,因此可以对于每个 u,把所有的 Fu,i,Gu,i 看成两个长度为 n 的序列 Fu,Gu 总体维护

那么整个状态转移的过程可以拆解成如下的步骤:

  • Fu[1n]1
  • 对于所有 i[1,au],令 Fu[i]Fu[i]×x0
  • 枚举 u 的所有儿子 v
    • 对于所有 i[1,n],令 Fv[i]Fv[i]+1
    • 对于所有 i[1,n],令 Fu[i]Fu[i]×Fv[i],Gu[i]Gu[i]+Gv[i]
  • 对于所有 i[1,n],令 Gu[i]Gu[i]+Fu[i]

具体的维护过程可以考虑用对于每一个节点 i 维护两个关键字 (f,g)

而我们发现在序列上每一次的操作都可以表示成形如 (f,g)(a×f+b,c×f+g+d) 的形式

我们可以从矩阵乘法的角度来理解这个标记的变换,容易构造出如下的转移矩阵:

[ac0010bd1]×[000010fg1]=[000010a×f+bc×f+g+d1]

更一般地,而我们可以把任意两个转移矩阵的合并看成如下的过程:

[a2c20010b2d21]×[a1c10010b1d11]=[a1×a2a1×c2+c10010a2×b1+b2c2×b1+d1+d21]

注意到上面的过程等价于在原有的 (a1,b1,c1,d1) 的标记上复合一个 (a2,b2,c2,d2),由于矩阵左乘的过程具有结合律,因此我们可以用线段树来维护这些 (a,b,c,d) 的标记,并且 f=b,g=d

因此我们可以得到一种新的运算

(a1,b1,c1,d1)(a2,b2,c2,d2)=(a1×a2,b1×a2+b2,a1×c2+c1,b1×c2+d1+d2)

特别地,当我们只关心 f,g 的信息时,也可以写成:

(0,f,0,g)(a,b,c,d)=(0,a×f+b,0,c×f+g+d)

的单位元为 (1,0,0,0),任何标记 上这个标记依然不改变自身的值

那么我们维护 Fu,Gu 的每一步的过程都可以用 的形式表示出来:

  • Fu[1n]1,等价于 (0,1,0,0)
  • 对于所有 i[1,au],令 Fu[i]Fu[i]×x0,等价于 (x0,0,0,0)
  • 枚举 u 的所有儿子 v
    • 对于所有 i[1,n],令 Fv[i]Fv[i]+1,等价于 (1,1,0,0)
    • 对于所有 i[1,n],令 Fu[i]Fu[i]×Fv[i],Gu[i]Gu[i]+Gv[i],等价于 (Fv[i],0,0,Gv[i])
  • 对于所有 i[1,n],令 Gu[i]Gu[i]+Fu[i],等价于 (1,0,1,0)

因此维护 Fu,Gu 的所有操作都可以写成区间 某个标记或把两个序列对应位标记 起来的形式

可以考虑使用线段树来优化,将这两种操作分别转化成线段树上的区间修改和合并两棵动态开点线段树,这样单次状态转移的时间复杂度就被优化到了可以接受的程度

IV. 最终处理与总结

最后,我们要在 root 对应的线段树上查询每个节点上的标记的 d 值之和,作为对应的 H(x0) 的值

接下来,我们只需要通过 H(1),H(2),,H(n+1) 的点值还原一个 n 次多项式 H(x)

首先写出拉格朗日插值法的标准形式:

H(x)=i=1n+1H(i)jixjij

然后把能够预处理的常数项提取出来,并且把可以公共计算的部分保留,从而对式子化简可得:

H(x)=i=1n+1H(i)jixjij=i=1n+1H(i)ji(ij)×j=1n+1(xj)xi

注意到:

  • 系数 H(i)ji(ij) 可以对每个 iΘ(n) 的时间求出

  • 初始多项式 j=1n+1(xj) 直接暴力卷积可以在 Θ(n2) 的时间内求出

  • 每次除以 xi 的过程稍作模拟也可以用 Θ(n) 执行单次修改

因此我们在 Θ(n2) 的时间复杂度内就可以插出 H(x) 的系数表达

最终,我们的总时间复杂度是 Θ(n2logw),瓶颈在枚举 x0 并且对于每个 x0 在树上用线段树合并维护点值

Submission Link


B. [IOI2022] 数字电路

Problem Link

首先,我们把计数问题转成概率问题,假设每个点的阈值是对应范围内的一个随机整数,用 fu 表示此时 u 的值为 1 的概率

考虑 u 的所有儿子 vson(u),我们能求出 son(u)1 的期望数量,设 cu 表示 son(u)1 的个数,那么:E(cu)=vson(v)fv

接下来考虑如何通过 E(cu) 推出 fu,我们可以把 E(cu) 按定义对于不同的 cu 给拆开,即令 gu,i 表示 son(u) 中出现恰好 i1 的概率,设 |son(u)|=su,那么我们有 i=1sui×gu,i=E(cu),这是根据期望的定义推出的

显然,为了求出 fu,我们只需对于每个 i[1,su] 求出:当 son(u) 中有恰好 i1 时,u 的值为 1 的概率,显然,此时阈值应该 i,而阈值的总取值共有 su 种,因此此时有 isu 的概率使得 u 的值为 1,将对应的 i 的贡献相加得到:fu=i=1suisu×gu,i

联立两式,我们知道 fu=1sui=1sui×gu,i=E(cu)su=1suvson(v)fv,因此我们得到了 fu 的转移

注意到 fu 的转移形式是线性的,因此每个叶子结点对 f0 的贡献也是线性的,准确来说:某个叶子 vf0 的贡献是 upath(v,0)1su(忽略 su=0 的项,即不考虑叶子结点的贡献)

回到原来的计数问题上,某个叶子 v 对答案的贡献就是 upath(v,0)su,直接预处理出每个叶子对答案的贡献,注意到只有值为 1 的叶子对答案有贡献,因此用线段树维护区间反转,统计(有贡献的叶子的)整体和的操作即可

注意题目给出的模数不支持求逆元,因此可能要预处理子树内的 su 积,再用 dfs 逐个转移出每个叶子对答案的贡献

时间复杂度 Θ((m+q)logm)

Submission Link


C. [BJOI2018]二进制

Problem Link

首先我们对原有的条件进行分析,注意到 22kmod3=1,22k1mod3=2

因此,对于一个二进制数 S,我们用 x0 表示 S0+S2+S4+,用 x1 表示 S1+S3+S5+,那么 Sx0x1(mod3)

又因为对于一个给定的区间,无论怎么重排,x0+x1 总是定值,那么我们可以通过对 x0+x1 的分析入手:

  • x0+x1mod2=0,直接使得 x0=x1 即可,即重排成一个形如 0000011111 的串其中串末尾恰好有偶数个 1,而相邻的两个 1 可以看成 2k+1+2k=3×2k 的形式,因此这个数必然是 3 的倍数
  • x0+x1mod2=1,由于 x0x1x0+x11(mod2)x0x1S3(mod3),因此 |x0x1| 至少是 3,因此首先要保证 x0+x13,注意到我们可以构造一个形如 00000111111110101 的串,此时 x0x13 个,且使用的 0 至少 2 个,可以证明不存在仅使用一个 0 而使得 x0+x1mod3=0 的方案

我们发现对符合条件的区间计数比较麻烦,考虑反面考虑,对满足如下两个条件至少之一的串 S 进行计数:

显然,满足这两个条件中的任意一个的都是不合法的 S,但由于这两个条件有相交部分,因此我们可以想到用容斥原理来计算,分别计算满足如下条件的 S 的数量:

  • S 中有奇数个 1,且 0 的个数 1
  • S 中只有一个 1
  • S 中只有一个 1,且 0 的个数 1

算出满足条件一、二的 S 的数量再减去满足条件三的 S 的数量即可

首先解决满足条件一的 S 的数量:

先考虑一个简单的 dp,用 fi,j,k 表示以 i 结尾,其中 1 的个数 mod2 的余数为 j0 的个数恰好为 kS 的数量

注意到只有 0k1 的情况有用,而我们要统计的答案为 Fi=jifi,1,0+fi,1,1 因此我们可以写出如下的转移方程:

  • ai=0 时:

{fi,0,0=0fi,0,1=fi1,0,0+1fi,1,0=0fi,1,1=fi1,1,0Fi=Fi1+fi,1,0+fi,1,1=Fi1+fi1,1,0

  • ai=1 时:

{fi,0,0=fi1,1,0fi,0,1=fi1,1,1fi,1,0=fi1,0,0+1fi,1,1=fi1,0,1Fi=Fi1+fi,1,0+fi,1,1=Fi1+fi1,0,0+fi1,0,1+1

显然想到可以用矩阵来维护这个转移过程:

  • ai=0 时:

[fi1,0,0fi1,0,1fi1,1,0fi1,1,1Fi11]×[001010000110100000010000000010001011]=[0fi1,0,0+10fi1,1,0Fi1+fi1,1,01]

  • ai=1

[fi1,0,0fi1,0,1fi1,1,0fi1,1,1Fi11]×[001010000110100000010000000010001011]=[fi1,1,0fi1,1,1fi1,0,0+1fi1,0,1Fi1+fi1,0,0+fi1,0,1+11]

初始向量为 [000001]

同理,对于第二个条件,我们也可以做类似的分析:

gi,j 表示以 i 结尾且其中恰好有 j1 的方案数,而我们要求的是 Gi=jigi,1,可以写出如下的转移方程:

  • ai=0 时:

{gi,0=gi1,0+1gi,1=gi1,1Gi=Gi1+gi,1=Gi1+gi1,1

  • ai=1 时:

{gi,0=0gi,1=gi1,0+1Gi=Gi1+gi,1=Gi1+gi1,0+1

把这两个转移写成矩阵的形式就是:

  • ai=0 时:

[gi1,0gi1,1Gi1]×[1000011000100001]=[gi1,0+1gi1,1Gi1+gi1,11]

  • ai=1 时:

[gi1,0gi1,1Gi1]×[0110000000100111]=[0gi1,0+1Gi1+gi1,0+11]

初始向量为 [0001]

因此这两个条件可以看成最标准的动态 dp 的形式,用线段树维护单点修改和区间求矩阵积两种操作即可

接下来考虑第三个条件,这个条件的分析就很简单了:

  • S 中只有一个 1:直接用树状数组维护一下区间内 1 的个数即可统计
  • S 中有 1110:对于每一对 (ai1,ai),维护 [ai1ai] 作为 i 的贡献,查询只需要查询 (l,r] 范围内的贡献和即可

综上所述,我们可以把所有的操作用线段树或树状数组来维护

时间复杂度 Θ(δ3(n+q)logn),其中 δ 为动态 dp 中转移矩阵的大小,此处 δ=6

Submission Link


D. [CCC2018] 最大战略储备

Problem Link

首先把每个城市看成一个节点,那么所有的节点可以看成一个矩阵的形式,每个城市可以用一个二元组表示 (i,j),其中同一个星球的城市在同一行(i 相同),在星球中的相对标号相同的城市在同一列(j 相同),那么原图中的每条边一定是形如如下两种边之一:

  • 对于某两行 x,y,对于所有列 j,连接 (x,j),(y,j),称作“竖边”
  • 对于某两列 x,y,对于所有行 j,连接 (i,x),(i,y),称作“横边”

显然原问题等价于在矩阵中求最小生成树

考虑继续用 Kruskal 算法,按边权将所有的边从小到大排序,手动模拟几次的过程:

  1. 假设第一条边是横边 (x1,y1),那么可以直接连接所有的 (x1,j),(y1,j)
  2. 假设第二条边也是横边 (x2,y2),那么根据 Kruskal 的定义,假如 (x2,y2) 所在的列不连通就可以连接所有的 (x2,j),(y2,j)
  3. 假设第三条边是竖边 (x3,y3),我们需要对所有 (i,x3),(i,y3) 连边,但是由于有一些竖边可能会和横边构成环(例如 (x1,y3)(x1,y3)(y1,y3)(y1,x3)(x1,x3)),观察后可以发现,每一行中的连通块,我们只需要挑一个点连接竖边
  4. 假设第四条边是横边 (x4,y4),首先我们要判断 (x4,y4) 所在的列是否联通,然后我们要注意 x4y4 列中同样的连通块只要连一个,因此这就和每一列的联通情况有关,容易想到一个断言:每一列的联通情况都是一样的,这是显然的,只要观察到:在第三次的过程中,没连接的竖边实际上的两个端点也是联通的,因此我们可以在此时将这条竖边看做联通的,因此对于每个列的联通情况只需要一个并查集就可以维护了

每次加入新横边的时候,连边的数量就是列的连通块数量,然后再连接对应的两个列,加入横边同理

因此我们只需要对于行和列分别维护并查集即可维护答案

时间复杂度 Θ((p+q)log(p+q))

Submission Link


E. [HNOI/AHOI2018] 寻宝游戏

Problem Link

首先对每个二进制位分别考虑,要注意到如下的观察

  • 0and1=0,1and1=1 以及 0or0=0,1or0=1,即 and1or0 操作不影响原数的值
  • 0and0=0,1and0=0 以及 0or1=1,1or1=1,即 and0or1 会将数值直接推平成操作数的值

显然,对于每个位最终的结果,一定是只由最后一个 and0or1 操作确定的

我们有这样的一个构造:把一个长度为 n 的操作序列看成 01 序列 O,其中 and1,or0

考虑某一位 i 上的 n 个数从小到大顺次构成的数值序列 Di,我们把操作序列和数值序列取反,发现答案的第 idi=[O<Di],其中 < 表示比较字典序

事实上,这个观察很好理解,从后往前逐位考虑,如果最高位不同,那么 O<Di 就代表最后一组操作是 or1,此时 di=1,否则代表 and0,此时 di=0,因此此时 di=[O<Di] 成立

如果最高位相同,那么比较次高位,等价于最后一组操作是 and1or0,这并不改变 di,因此结果依赖于倒数第二次操作后的 di,等价于比较次高位,如果最终 O=Di,那么表示全程没有修改,di 直接为初值也就是 0,简单做数学归纳法即可证明这个命题的正确性

我们先预处理出每个位 in 个数从大到小逆序排列所对应的数值序列 Di,对于当前 r 的某个数位 iri=0 表示 DiO,否则表示 Di>O,因此 O 可以表示成 O[Dl,Dr) 的形式

注意到预处理出 Di 按字典序的排名以及 Di 作为二进制数所表示的对应的实际数值 int(Di),那么答案就是 int(Dr)int(Dl),可以直接快速计算(注意 Dr<Dl 时答案为 0

注意在无下界的情况下用全 0 串代替 Dl,在无上界的情况下用 2n,即 (10000n times) 代替 Dr

时间复杂度 Θ(nmlogm+qm)

Submission Link


F. [JXOI2018] 守卫

Problem Link

考虑区间 dp:用 dpl,r 表示查询区间 [l,r] 的答案,我们有一个显然的观察:所有保镖覆盖的位置一定小于其所在的位置,那么 r 一定在方案中

因此考虑 [l,r]r 看到的最左边的点 p,可以证明:为了覆盖 p1,在位置 p 和位置 p1 上至少有一个位置有保镖

那么可以按照 [l,p](或 [l,p))和 (p,r] 分裂成两段,能够证分裂出来的两段之间不会有位置存在相互看见的关系,因此答案就是 min(dpl,p1,dpl,p)+dpp+1,r

枚举右端点,左端点从大到小移动并维护 p 即可

时间复杂度 Θ(n2)

Submission Link


G. [JSOI2018] 列队

Problem Link

容易证明的贪心是:当编号在 [l,r] 之间的学生列队之后,他们之间左右的相对顺序是不会改变的

因此我们可以用 pi 表示第 i 个人在 [k,k+rl] 中排在第 pi 位,答案就是 lir|piai|,考虑把绝对值拆开,答案变成 pi>aipipi>aiai+piaiaipiaipi

注意到 pi 是一段连续自然数,并且最小值(或最大值)已知,只需要知道满足条件的 i 的个数即可,第二个问题也非常简单,建立主席树即可解决

问题只剩下找到 ai 的临界值,显然,我们在主席树上二分,通过统计某一个值域段中的 ai 的数量来判断 pi 的位置并决定下一步递归左子树还是右子树,查询答案时也只需要用给定的值域在主席树上求出 ai 的数量和 ai 的和即可

时间复杂度 Θ((n+m)logn)

Submission Link


H. [eJOI2019] 塔

Problem Link

首先假设我们每次操作的都是之前的整个区间,容易发现生成的序列为 1,1,2,4,8,

根据值域的放缩,假设操作次数为 k,容易发现一个 k 的下界是 log2q+2,考虑如何构造一个满足这样下界的操作序列

注意到当我们在加入第 i 个数字时,选择的区间从 [1,i) 变成 [2,i),那么 aiai1,对后续的影响为 1,1,2,4, 那么 ai 对最后一位产生 2ki1 的影响

那么我们修改 a1ak1 最终对答案的贡献就是 202k1,显然足够凑出 2log2qq 的值

故直接对于每一个位判断从 1 还是 2 开始即可

时间复杂度 Θ(Tlogq)

Submission Link


I. [JXOI2018] 排序问题

Problem Link

首先转化题目中的条件,假设我们有一个长度为 n 的序列,且值 i 的出现次数为 ci,那么合法的序列应该有 ici! 种,因此单次排序成功的概率为 ici!n!,最终成功的期望次数为 n!ici!=(nc1,c2,)

由于 n 给定,我们的目标就是最小化 ici!,显然不在 [l,r] 内的 i 对答案的贡献是确定,因此只需要最小化 lirci! 的值,又由于 lirci 是定值,因此我们只需要让所有的 ci 尽可能平均即可,显然可以二分这个平均值,然后暴力判断即可

预处理出所有的阶乘即可解决

Vn+m 的值域,wrl+1 的值域,时间复杂度为 Θ(V+nlogw)

Submission Link


J. [八省联考 2018] 劈配

Problem Link

首先匹配问题第一步显然想到网络流:从源点向所有选手 i 连容量为 1 的边,从所有老师 j 向汇点连容量为 bj 的边

匹配每个人最终志愿的时候考虑增量算法:对于每次新增选手 i,从小到大枚举他的每一档志愿 j,每次将 i 与他的 j 档志愿中的老师连接一条容量为 1 的边,如果在当前的图中搜出增广路,立刻停止,并找用 EK 算法一条增广路流向汇点,否则删除这些边,考虑 j+1 档志愿

第二问也类似,在匹配 i 之前,对于所有 i 的人 j 判断当他们此时连接 1sk 档志愿能否得到增广路,如果能就用 ji 更新答案,注意此时的所有边都要删除,也不要用 EK 增广

单次搜索找增广路的时间复杂度是 Θ(nC) 的,对于第一问,每个人要找 Θ(m) 次增广路,对于第二问,每次有 Θ(n) 个人要找增广路,因此时间复杂度是 Θ(n2(n+m)C)

Submission Link


K. [APIO2020] 有趣的旅途

Problem Link

注意到 dist(u,v)LCA(u,v) 有关系,比较不好处理,因此考虑定根,即选定一个点 root 作为根,使得所有 LCA(pi1,pi)=root

注意到此时我们选择的相邻的 pi 就需要来自 root 的不同的两棵子树,因此一个自然的想法是让 root 的各子树大小尽可能接近

为了让子树大小尽可能接近,我们想到了树上的一个特殊点——重心,容易发现,重心在这里具有非常好的性质:当 root 只有两棵子树 TA,TB 时,|TA|+|TB|n2,|TA|+|TB|=n1,我们能发现此时 (|TA|,|TB|) 的差至多为 1,此时直接交替选择 TA,TB 中深度最大的点即可

接下来我们需要处理 root 有三棵子树 TA,TB,TC 的情况,首先依然想到承袭上面的思路,每次选择上一次未被选择的两棵子树中深度最大的节点,不过这个做法可能有问题,当某个时刻有两棵子树都被删空之后,我们将无法继续进行这个操作

注意到如下的观察:

当我们不断执行如上操作并且最终会剩下一棵子树时,在这个过程中,总存在某个时刻,使得 root 的某棵子树大小恰好等于另外两棵子树大小之和

假如这个观察成立,那么我们可以在在这个时刻把这两棵子树合并,转化为两棵子树的情况,不过一种需要特殊注意的情况:假设当前 |TA|=|TB|+|TC|,并且我们上一次选的节点是 TB,且此时 TC 子树的最大深度大于上一个节点的深度,正常情况下我们会选择 TC,但在合并 TB,TC 之后,我们会选择 TA,此时要先选择 TC 中深度最大的节点再操作才可保证正确性

下面给出这个观察的证明:

证:

对于某个时刻,我们定义函数 f(TA,TB,TC)=|TA|+|TB|+|TC|2×max{|TA|,|TB|,|TC|}

显然,最开始由于 root 是重心,因此 max{|TA|,|TB|,|TC|}n2,因此 f(TA,TB,TC)(n1)2×n2=1

而我们要证明的是存在某个时刻 f(TA,TB,TC)=0,首先,当 f(TA,TB,TC)=1 时,直接操作大小最大的子树即可

在剩下的情况中, f(TA,TB,TC) 的变化量 Δ 分为以下几种:

  • 操作的子树 T 是最大子树,操作完还是最大子树,此时 Δ=1
  • 操作的子树 T 是最大子树,操作完不是最大子树,此时 Δ=1
  • 操作的子树 T 不是最大子树,此时 Δ=1

综上,f(TA,TB,TC) 在整值值域上连续,而当最终我们留下一棵子树 T 不删空时,一定有 f(TA,TB,TC)=|T|<0,因此 f(TA,TB,TC) 从正值变化到负值的过程中一定会经过 f(TA,TB,TC)=0,即某个子树大小等于另外两个子树大小之和的情况

综上所述,对于 TA,TB,TC 排序后就可以解决这个问题

接下来考虑如何利用交互库:

  • 首先求出树的重心,我们可以先随意指定一个根(假设为 0),然后调用 attractionsBehind(0,i) 得到此时 i 的子树大小 sizi,找到 nsizin2sizi 最小的 i 即为重心
  • 求出 root 的儿子 A,B,C,显然调用 hoursRequired(root,i) 得到每个点的深度 depidepi=1 的即为 root 的儿子
  • 将所有顶点划分到 TA,TB,TC 中,调用 hoursRequired(A,i)hoursRequired(B,i) 求出 dist(A,i),dist(B,i),设 iX 的子树里,那么显然 dist(X,i)+1=depi,且 A,B,C 中这样的 X 有且仅有一个,故判断 A,B 是否满足,若均不满足则 X=C

综上,我们的总操作次数是 4×n 的,可以通过本题

时间复杂度 Θ(nlogn)

Submission Link


L. [ZJOI2018] 胖

Problem Link

disi 表示 1i 的距离,那么任意两个点 i,j 的距离是 |disidisj|

考虑某个 ai 能够更新的范围,对于某个 x(假设 xai),ai 能够更新 x 当且仅当 [2×xai,ai) 中不包含比 ai 更优的决策点,即:

  • 对于所有 aj[2×xai,x),有 cj+disxdisaj<ci+disaidisx 成立
  • 对于所有 aj[x,ai),有 cj+disajx<ci+disaidisx 成立

注意到 x 显然有可二分性,因此二分 x,检验的时候用 ST 表维护对应两个区间中的 cj±disaj 最小值并比较检验即可,注意 ST 表每次只维护给定的 m 个元素,因此在 ST 表上查询的对应区间需要通过二分得到

类似地可以二分出 ai 可以更新的区间的右端点,因此枚举每个 i 二分得到其有贡献的区间并求和即可得到答案

特别地,当某两个 ai,aj 更新 x 的代价相同且 |xai|=|xaj| 时,我们会漏统计此时的贡献,在二分左端点或右端点其中之一时检验时特判这种情况并判为可行即可

时间复杂度 Θ(n+KlogKlogn)

Submission Link


M. [HAOI2018] 染色

Problem Link

首先可以先解出:有 k 种颜色恰好出现了 s 次的方案数 fk

fk=(mk)×n!(ns×k)!×(s!)i×(ns×k)mk

假设恰好有 k 种颜色出现而恰好 s 次的方案数为 gk,根据广义容斥原理,我们有:

gk=j=km(1)jk(jk)fj

对组合数进行展开并且稍作变形可以得到:

gk=j=km(1)jk(jk)fj=j=km(1)jkj!(jk)!×k!×fj=1k!j=km(1)jk(jk)!×(j!×fj)

注意到求和式里面的东西只和 jk,j 有关,设 ak=(1)kk!,bk=k!×fk,那么原式可以进一步化简成:

gk=1k!i=0mj=0m[ij=k]×bi×aj

注意到两个变量的差是定值,因此容易想到将一个变量取反使得和变为定值,即令 bk=bmk,那么有:

gk=1k!i=0mj=0m[i+j=mk]×bi×aj

此时可以发现这是一个卷积的形式,因此 gmk 的生成函数可以由 bmk 的生成函数和 ak 的生成函数卷积得来,一次 NTT 即可求出所有 gk,统计贡献并求和即可

时间复杂度 Θ(n+mlogm)

Submission Link


N. [CQOI2018] 破解D-H协议

Problem Link

用 BSGS 解出满足 gxA(modP)x,答案即为 BxmodP

时间复杂度 Θ(nPlogP)(BSGS 内部用哈希表存储可以做到 Θ(nP)

Submission Link


O. [BalticOI2019] 潜艇

Problem Link

bitset 维护每个位置当前是否可以作为结束位置,用左右移位模拟潜艇向四个方向移动的过程,注意在移动之前要把第一列/第一行/最后一列/最后一列的位置设为不可达再移动,不然可能会越界

时间复杂度 Θ(M×RCω)

Submission Link


P. [CQOI2018] 九连环

Problem Link

fi 表示拆下 i 个环的最小步数,gi 为装上 i 个环的最小步数

考虑 fn 求解的过程:首先我们要拆下前 n2 个环,然后拆下第 n 个环,然后装上前 n2 个环并拆下前 n1 个环,因此有 fn=fn2+1+gn2+fn1,同理也可得 gn=gn1+fn2+1+gn2,且 f0=g0=0,f1=g1=1,根据归纳法我们知道 fn=gn,因此我们只需要解递推式 fn=fn1+2fn2+1 即可,其中 f0=0,f1=1

显然对 fi 建立生成函数 F(x),有如下推导:

F(x)=i=0fi×xi=f0×x0+f1×x1+i=2fi×xi=x+i=2xi(fi1+2fi2+1)=x+x(i=1xi×fi)+2x2(i=0xi×fi)+i=2xi=i=1xi+xF(x)+2x2F(x)=x1x+xF(x)+2x2F(x)=x(1x)(1x2x2)=x(1x)(1+x)(12x)=121x+161+x+2312x=16i=0[22n+23(1)i]xi

因此我们得到 fi=22n+23(1)i6,用 FFT 优化快速幂可以通过本题,时间复杂度 Θ(mnlog2n)

事实上,我们用压位高精也能通过本题,并且在压位较多时有较优秀的表现

时间复杂度 Θ(mL2logn),其中 L 表示答案的位数,在压 9 位高精时,L3000,可以通过本题

Submission Link


Q. [WC2018] 州区划分

Problem Link

显然考虑状压 dp,用 S 表示状压点集,dpS 表示划分点集 S 的答案,用 valid(S) 表示 S 表示的点集可以划分在一个州区,即 S 这个点集的导出子图不存在欧拉回路(注意要同时判断连通性和度数)用 cost(S) 表示 S 中的节点 w 值之和,状态转移方程如下:

dpS=TS[valid(T)]×dpST×cost(T)cost(S)

其中边界条件为 dp=1,稍作变化可以写成下式:

dpS=1cost(S)A,B[AB=S]×[AB=]×([valid(A)]×cost(A))×dpB

注意到 AB=S 是一个标准的或运算 FWT 的形式,因此我们考虑用 FWT 优化转移的复杂度,注意到比较难处理的是 AB=,不过我们可以考虑用 |A|+|B|=|S| 来约束,也就是用 dp|S|,S 来表示状态,转移 dpk 的时候从所有 i+j=kdpicostj 处转移, 表示位运算卷积

时间复杂度 Θ((n2+m)2n)

Submission Link


R. [省选联考 2021 B 卷] 取模

Problem Link

先考虑对于固定的模数 p 如何解决该问题,令 ri=aimodp(ri+rj)modp 的值有两种可能:ri+rjri+rjp,对于第二种情况,直接选择最大和次大的 ri,rj 即可,对于第一种情况,我们用双指针或二分对每个 ri 找到小于 pri 的最大 rj 并统计即可

注意到这样的单次操作时间复杂度是 Θ(nlogn) 的,考虑剪枝,两个显然的剪枝分别是:

  • 从大到小考虑模数 ai,当当前 ai 不超过答案时,直接停止更新
  • 对于多个相同的 ai 只考虑一个

在使用了这两个优化之后,枚举次数变成 Θ(logw) 级别,其中 wai 的值域,证明如下:

证:

假设在求出答案之前,枚举过的模数从小到大依次是 ans<p1<p2<<pk,那么根据第一个剪枝,显然 pi1+pi2pi,否则 pi1+pi2<pi,因此 ans>pi1+pi2>pi1>pi2 与第一个剪枝矛盾

因此我们得到 ans(pi1+pi2)modpipi1+pi2pi,从而推出 (pians)>(pi1ans)+(pi2ans)

由于上式我们可以得到 p1anspkans 的增长速度超过斐波那契数列,由于比内公式我们知道斐波那契数量成指数级增长,因此 k 的个数是 Θ(logw) 级别的,原命题得证

时间复杂度 Θ(nlognlogw)

Submission Link


S. [CTSC2018] 假面

Problem Link

考虑先处理第一个操作,显然用 dpi,j 表示第 i 个人当前剩余生命值为 j 的概率,显然以 p 的命中概率每次攻击某个人 i,有转移 dpi,j(1p)×dpi,j+p×dpi,j+1,特别地,dpi,0dpi,0+p×dpi,1

显然在已知 dpi,j 的基础上,求出最终每个人的剩余生命的期望也可以轻松求出

接下来只需要解决技能命中的问题,显然我们只关心一个人是否存活,记第 idi 个人存活的概率为 pi,显然 pi=1dpi,0,接下来我们需要对于每个 idi,计算除了 idi 之外恰好有 0,1,2,,k 个人存活的概率,显然可以看成一个有关存活人数的背包

看到背包问题显然想到多项式优化,定义多项式 Fi(x)=jipjx+(1pj),我们只需要求出所有 Fi(x) 即可,观察到这是一个回撤背包的形式,先求出 F(x)=jpjx+(1pj),每次计算 i 的时候只需要用 F(x) 除以 pix+(1pi) 即可得到 Fi(x),这两步的卷积可以直接暴力解决,注意当撤回贡献时若存在 pi=01pi=0 的特殊情况可能要特判

时间复杂度 Θ(Cn2+Qw),其中 wmi 的值域

Submission Link


T. [NOI2018] 归程

Problem Link

在使用车之后,Yazid 可以从 u 通过无积水边到达的整个连通块的任意一个点开始,步行前往 1,因此答案是这个连通块中的点到 1 的距离最小值,先用 Dijkstra 预处理一遍所有的 dist(1,i) 即可快速求解

接下来只需要维护从 u 出发,经过海拔 >h 的边能到的连通块,显然考虑 Kruskal 重构树,边权按海拔从大到小排序,建出 Kruskal 重构树,在重构树上倍增,求出权值 >h 的最高点,其子树对应的连通块即为所求,而快速维护对应子树的最小值,不需要 RMQ,只需要在 Kruskal 合并两棵子树的时候把对应子树的最小距离也一起合并到父亲上即可

时间复杂度 Θ(mlogm+qlogn)

Submission Link


U. [HNOI/AHOI2018] 游戏

Problem Link

显然每个点 i 能到达的是一段连续的区间 [li,ri],回答询问时只需要判断 t[ls,rs] 是否成立即可

我们考虑最暴力的拓展,假如可以向左走就向左拓展,可以向右走也一样向右拓展,注意到每个位置向左走之后的节点在拓展完之后可以记忆化,即当 ii1 可行时,li1li 一定成立,li 可以直接从 li11 去拓展,注意到 li 的指针是不断左移的,因此可以证明时间复杂度是线性的,同理,向右拓展的时间复杂度也是线性的

综上所述,我们只需要记忆化并暴力搜索拓展即可

时间复杂度 Θ(n)

Submission Link


V. [HNOI/AHOI2018] 排列

Problem Link

首先我们有一个观察:某个 ai 表示在 p 中,ai 一定要在 i 之前出现,因此连接所有 iai,形成的应该是一棵以 0 为根的树,否则显然无解

接下来考虑 1 的位置,显然的观察是 1 一定要尽可能早选,也就是当 1 的父亲被选择之后一定要立刻选 1

因此我们可以把 11 的父亲看成一个连接的序列,这样我们每次都相当于在整个树中找一个价值最小的序列把这个序列和其父亲连接起来

接下来我们要判断哪个序列价值最小,假设一个序列 x 中节点的数量为 sizx,权值和为 wx,那么对于两个序列 a,bwabwba=wb×sizawa×sizb,因此 ab 先被取出合并当且仅当 wa×sizb<wb×siza,注意到这实际上等价于 wasiza<wbsizb,即比较平均值,因此这个比较是全序的,直接用 set 维护所有节点即可

时间复杂度 Θ(nlogn)

Submission Link


W. [IOI2020] 连接擎天树

Problem Link

注意到 pi,j{0,1,2} 时很好解决,图一定是一个基环树森林的形式:

  • pi,j=0,则表示 i,j 不在同一棵基环树中
  • pi,j=1,则表示 i,j 在同一棵基环树的同一棵子树中
  • pi,j=2,则表示 i,j 在同一棵基环树的不同子树中

接下来考虑 pi,j=3 的情况,显然至少要在基环树的基础上添加一条边,那么至少会额外形成一个环,可以发现,在有两个环的基环树中,我们总能找到一组点对 (u,v) 满足 uv 的路径有 4 条,因此我们可以断言:存在 pi,j=3 时原问题无解

接下来考虑如何实现代码,首先判断 pi,j=3 的情况,然后用并查集处理 pi,j=0 的情况,把 pi,j0 的加入一个连通块,并判断同个联通块是否有 pi,j=0 的情况,如果有则返回无解

接下来考虑 pi,j=2 的情况,重新初始化并查集,把 pi,j=1 的加入同一个连通块,并判断同个连通块是否有 pi,j=2 的情况,如果有则返回无解,然后把同一个连通块的点连成链,把不同连通块的代表元提取出来连成一个环,需要特判环的大小 =2 的情况,此时若形成环必然需要重边,不符合题意,直接报告无解即可

时间复杂度 Θ(n2α(n))

Submission Link


X. [eJOI2019] 挂架

Problem Link

首先将挂钩的下标转成二进制下的 02n1,并模拟 n=3 时的操作顺序:000100010110001101011111,我们可以看到,最高位以 20 为周期切换 01,次高位以 21 为周期切换 01,其他位同理

事实上,最高位每次切换相当于维持第一层的 20 根平衡杆平衡,次高位每次切换相当于维持第二层的 21 根平衡杆平衡,其他位同理,因此答案的每一位上是 0 还是 1 可以直接取出其对应位的值就可以确定,最后再在 mod109+7 意义下逐位还原答案即可,注意处理时下标是 0 开始标号的,因此读入的 k 要减一,输出的答案要加一

时间复杂度 Θ(n+logk)

Submission Link


Y. [WC2021] 括号路径

Problem Link

定义 valid(u,v) 表示 uv 是一条合法括号路径,则如下的结论是显然的:

  • 双向性:valid(u,v)valid(v,u)
  • 可传递性:valid(u,v)valid(v,w)valid(u,w)

因此我们可以把 valid(u,v) 想象成 u,v 的连通性,用并查集维护,而每次拓展时只需要找到两条 (x,u,w),(x,v,w) 的边即可把 u,v 缩成一个点,先用 map 维护每个点每种颜色的出边,合并用 BFS 逐步维护即可

每次合并两个点 u,v 时维护一下出边,把能合并的 (u,u,w),(v,v,w) 也合并起来,这一步需要用启发式合并来保证复杂度,每次每个点的出边集至少扩大两倍,这样总体复杂度是 Θ(mlogm) 的,足够通过本题

时间复杂度 Θ(mlogklogm)

Submission Link


Z. [省选联考 2021 A 卷] 矩阵游戏

Problem Link

注意到没有值域限制的问题是很显然的,直接假设 aj,m=an,i=0,剩下的可以从后往前逆序递推

接下来考虑解决 [0,106] 的值域限制,注意到对于某一行或某一列,只有交替地进行 +x,x 的操作才保证不影响答案,假设第 i 行的变化量为 +ri.ri,+ri,,第 j 列的变化量为 +cj,cj,+cj,,那么 ai,j 的变化量 Δi,j 有以下 4 种可能:

  • 2i,2j 时:Δi,j=ricj
  • 2i,2j 时:Δi,j=ricj
  • 2i,2j 时:Δi,j=cjri
  • 2i,2j 时:Δi,j=ri+cj

并且我们发现限制条件可以写成 ai,jΔi,jAai,j,其中 A=106,因此考虑用差分约束解决此问题,不过注意到有两种情况的 Δi,j 是和的形式,因此我们考虑对 2iri2jcj 取反得到 xi,yj,得到 Δi,j 的变化形式为:

  • imod2jmod2 时:Δi,j=yjxi
  • imod2=jmod2 时:Δi,j=xiyj

因此我们可以把 xi,yj 用差分约束系统表示,用 SPFA 求解即可

时间复杂度 Θ(nm(n+m))

Submission Link

posted @   DaiRuiChen007  阅读(114)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示