T1

100%

用循环模拟 tt 分钟的时间变化,维护当前时间 xxyy 分:

  • 先是分钟 y=y+1y=y+1
  • 如果当前分钟 y=60y=60,说明到了下一个小时,那么小时 x=x+1x=x+1,分钟 y=0y=0
  • 如果当前小时 x=24x=24,说明到了下一天,那么小时 x=0x=0

循环 tt 次后的时间 xxyy 分即为答案。

时间复杂度 O(t)O(t)

T2

100%

两重循环枚举点 ii 和点 jj,维护距离点 ii 最近的点的编号 ans[i]ans[i],距离点 ii 最近的点有多个时 ans[i]ans[i] 选其中编号最小的。

在判断距离关系时,可以直接比较距离的平方,不需要开根号。

时间复杂度 O(n2)O(n^2)

T3

100%

将每个订单的编号 nono、提交时刻 aa 和花费时间 tt 三个属性放在结构体 pp 里,把 ppaa 从小到大的顺序排序。

用循环模拟订单提交和处理的过程,维护之前提交的订单中最后一个订单完成的时刻 nownow,初始 now=0now=0,对于第 ii 个提交的订单 p[i]p[i]

  • 如果 nowp[i].anow\leq p[i].a,说明当前订单提交时没有正在处理的订单,那么从 aa 时刻开始处理当前订单,将会在 p[i].a+p[i].tp[i].a+p[i].t 时刻完成,更新最后一个订单完成的时刻 now=p[i].a+p[i].tnow=p[i].a+p[i].t
  • 如果 now>p[i].anow>p[i].a,说明当前订单提交时还有其他订单正在处理,那么当前订单会取消,将当前订单的编号 p[i].nop[i].no 添加到数组 ansans 中。

循环结束后,如果数组 ansans 的长度为 00,说明没有取消的订单,输出 Perfect;否则将 ansans 中的元素从小到大排序后输出。

时间复杂度 O(nlog(n))O(n\log(n))

T4

20%

对于求区间 [L,R][L,R] 的二维异或和的询问,用两重循环分别枚举 iijj 满足 Li,jRL\leq i,j\leq R,计算 i=LRj=LRAiAj\sum_{i=L}^R\sum_{j=L}^R A_i\oplus A_j

时间复杂度 O(qn2)O(qn^2)

60%

注意到计算两个数的异或结果 xyx\oplus y 时,二进制下的每一位是独立的。

这意味着如果只看二进制下第 kk 位,AiA_iAjA_j 不一样,那么 AiAjA_i\oplus A_j 在二进制下第 kk 位为 11。如果区间 (L,R)(L,R) 中有 xx 项在这一位为 11,那么剩下 (RL+1)x(R-L+1)-x 项在这一位为 00,因此对于 Li,jRL\leq i,j\leq RAiAjA_i\oplus A_j 在二进制下第 kk 位为 11 的有 x×((RL+1)x)x\times ((R-L+1)-x) 项。

定义函数 num(L,R,i)num(L,R,i) 表示区间 [L,R][L,R] 中有多少项在二进制下第 ii 位为 11

对于每个询问,分别计算二进制下每一位的答案,再加起来。对于二进制下第 ii 位,O(n)O(n) 计算 num(L,R,i)num(L,R,i),答案增加 $2 \times num(L,R,i)\times ((R-L+1)-num(L,R,i))\times 2^i$。

AiA_i 的最大值为 V=max{Ai}V=\max\{A_i\}

时间复杂度 O(qnlog(V))O(qn\log(V))

100%

维护 cnt[i][j]cnt[i][j] 表示区间 [1,i][1,i] 中有多少项在二进制下第 jj 位为 11

那么可以用差分的技巧 O(1)O(1) 计算 num(L,R,i)=cnt[R][i]cnt[L1][i]num(L,R,i)=cnt[R][i]-cnt[L-1][i]

时间复杂度 O((n+q)log(V))O((n+q)\log(V))

T5

20%

时间越长每个机器人的移动范围越大,能清理的垃圾也越多,所以可以二分答案。

定义函数 check(x)check(x) 来判断 xx 和答案的关系:

  • 如果花费 xx 的时间无法清理所有垃圾,说明答案大于 xx,这种情况函数返回 00
  • 如果花费 xx 的时间可以清理所有垃圾,说明答案小于等于 xx,这种情况函数返回 11

check(x)check(x) 时,11 类机器人和 22 类机器人的移动范围是固定的,对于第 ii 个机器人:

  • 如果是 11 类机器人那么移动范围是 aixa_i-xaia_i
  • 如果是 22 类机器人那么移动范围是 aia_iai+xa_i+x

对于测试点#1~2,只有第 11 个机器人是 33 类机器人,其余机器人都是 11 类机器人或 22 类机器人,且 n1000n\leq 1000m2000m\leq 2000。因此在 check(x)check(x) 时:

  • 先用两重循环分别枚举第 ii 个垃圾和第 jj 个机器人:
    • 如果第 jj 个机器人是 11 类机器人那么移动范围是 ajxa_j-xaja_j,所以如果 ajxbiaja_j-x\leq b_i\leq a_j 说明第 ii 个垃圾能被第 jj 个机器人清理,否则说明第 ii 个垃圾不能被第 jj 个机器人清理;
    • 如果第 jj 个机器人是 22 类机器人那么移动范围是 aja_jaj+xa_j+x,所以如果 ajbiaj+xa_j\leq b_i\leq a_j+x 说明第 ii 个垃圾能被第 jj 个机器人清理,否则说明第 ii 个垃圾不能被第 jj 个机器人清理;
  • 如果第 2n2\sim n 个机器人清理了所有垃圾, 说明花费 xx 的时间足够清理所有垃圾,checkcheck 函数返回 11
  • 否则用第 11 个机器人来清理这些没有被第 2n2\sim n 个机器人清理的垃圾,维护这些垃圾的坐标最小值 PLPL 和坐标最大值 PRPR,第 11 个机器人的方案有两种:
    • 先清理坐标为 PLPL 的垃圾,花费时间为 a1PL|a_1-PL|,再清理坐标为 PRPR 的垃圾,花费时间为 PRPLPR-PL,过程中会将坐标为 PLPRPL\sim PR 的垃圾一并清理掉,这个方案的总时间为 a1PL+PRPL|a_1-PL|+PR-PL
    • 先清理坐标为 PRPR 的垃圾,花费时间为 a1PR|a_1-PR|,再清理坐标为 PLPL 的垃圾,花费时间为 PRPLPR-PL,过程中会将坐标为 PLPRPL\sim PR 的垃圾一并清理掉,这个方案的总时间为 a1PR+PRPL|a_1-PR|+PR-PL
    • 因此用第 11 个机器人清理这些垃圾所需的最少时间为 min(a1PL,a1PR)+PRPL\min(|a_1-PL|,|a_1-PR|)+PR-PL
    • 如果 min(a1PL,a1PR)+PRPLx\min(|a_1-PL|,|a_1-PR|)+PR-PL\leq x,说明花费 xx 的时间足够清理所有垃圾,checkcheck 函数返回 11
    • 否则说明花费 xx 的时间不能够清理所有垃圾,checkcheck 函数返回 00

记坐标的最大值为 V=max{ai,bi}V=\max\{a_i,b_i\}

时间复杂度 O(log(V)nm)O(\log(V)nm)

40%

对于测试点#1~4,只有第 11 个机器人是 33 类机器人,其余机器人都是 11 类机器人或 22 类机器人,因此思路还是二分答案,在 check(x)check(x) 时先考虑用第 2n2\sim n 个机器人尽可能清理垃圾,对于没有被第 2n2\sim n 个机器人清理的垃圾,维护这些垃圾的坐标最小值 PLPL 和坐标最大值 PRPR,用第 11 个机器人在清理。

测试点#3~4的数据范围变为 n105n\leq 10^5m2×105m\leq 2\times 10^5,因此我们将 11 类机器人的坐标保存在数组 Pa1Pa1 中,将 22 类机器人的坐标保存在数组 Pa2Pa2 中,并将 Pa1,Pa2,bPa1,Pa2,b 这三个数组都从小到大排序,然后二分答案,在 check(x)check(x) 时使用双指针的技巧去处理 11 类机器人和 22 类机器人能够清理的垃圾:

  • 对于坐标第 ii 小的垃圾,分别找到最小的 j1j_1 满足 biPa1[j1]b_i\leq Pa1[j_1],和最小的 j2j_2 满足 biPa2[j2]+xb_i\leq Pa2[j_2]+x
    • 如果 Pa1[j1]xbiPa1[j1]Pa1[j_1]-x\leq b_i\leq Pa1[j_1] 说明第 ii 个垃圾能被 11 类机器人清理,否则说明坐标第 ii 小的垃圾不能被 11 类机器人清理;
    • 如果 Pa2[j2]biPa2[j2]+xPa2[j_2]\leq b_i\leq Pa2[j_2]+x 说明第 ii 个垃圾能被 22 类机器人清理,否则说明坐标第 ii 小的垃圾不能被 22 类机器人清理;
  • 如果 11 类机器人和 22 类机器人清理了所有垃圾, 说明花费 xx 的时间足够清理所有垃圾,checkcheck 函数返回 11
  • 否则尝试用唯一的 33 类机器人来清理这些没有被 11 类机器人和 22 类机器人清理的垃圾,参考第一部分。

时间复杂度 O((n+m)log(V))O((n+m)\log(V))

60%

对于测试点#5~6,所有机器人都是 33 类机器人,因此先将 aa 数组和 bb 数组都从小到大排序后,再二分答案,在 check(x)check(x) 时使用双指针的技巧,尝试用剩余机器人中坐标最小的去清理剩余垃圾中坐标最小的:

  • 如果坐标第 1i11\sim i-1 小的垃圾已经用坐标第 1j11\sim j-1 小的机器人清理了,那么考虑坐标第 ii 小的垃圾用坐标第 jj 小的机器人来清理;

  • 如果 biaj>x|b_i-a_j|>x,说明坐标第 ii 小的垃圾无法用坐标第 jj 小的机器人清理,继续尝试用坐标第 j+1j+1 小的机器人来清理这个垃圾;

  • 否则坐标第 ii 小的垃圾可以用坐标第 jj 小的机器人清理,考虑让这个机器人在清理这个垃圾的同时,尽可能清理更多垃圾,也就是求出这个机器人在需要移动到 bjb_j 的前提下,能移动到的最大坐标 FRFR,并用这个机器人将坐标为 ajFRa_j\sim FR 的垃圾一并清理掉;

  • 如果 ajxa_j\leq x,那么这个机器人会一直向右移动,FR=aj+xFR=a_j+x

  • 否则这个机器人的方案有两种:

    • 先向左移动到 bib_i 再向右移动,FR=max(aj,bi+(x(ajbi)))FR=\max(a_j,b_i+(x-(a_j-b_i)))
    • 先向右移动再向左移动到 bib_iFR=aj+x(ajbi)2FR=a_j+\frac{x-(a_j-b_i)}{2}
  • 如果坐标第 1m1\sim m 小的垃圾可以用坐标第 1n1\sim n 小的机器人清理,checkcheck 函数返回 11;否则 checkcheck 函数返回 00

时间复杂度 O((n+m)log(V))O((n+m)\log(V))

结合第二部分可以拿到 60%60\% 的分数。

100%

将第二部分与第三部分相结合:

  • 11 类机器人的坐标保存在数组 Pa1Pa1 中,将 22 类机器人的坐标保存在数组 Pa2Pa2 中,将 33 类机器人的坐标保存在数组 Pa3Pa3 中,并将 Pa1,Pa2,Pa3,bPa1,Pa2,Pa3,b 这四个数组都从小到大排序,然后二分答案;
  • check(x)check(x) 时:
    • 先处理 11 类机器人和 22 类机器人能够清理的垃圾,参考第二部分;
    • 再尝试用 33 类机器人来清理这些没有被 11 类机器人和 22 类机器人清理的垃圾,参考第三部分。

时间复杂度 O((n+m)log(V))O((n+m)\log(V))

T6

40%

对于第 ii 个炸弹,从节点 pip_i 出发进行 DFS\text{DFS} 将所有满足 dis(pi,j)widis(p_i,j)\leq w_i 的节点 jj 的答案 ans[j]ans[j] 都增加 11

时间复杂度 O(nm)O(nm)

100%

将节点 11 定义为树的根,把树转化为有根树。

定义函数 fa(x,i)fa(x,i) 表示从节点 xx 向根节点方向移动 ii 次后到达的节点。如果节点 xx 到根节点的距离 dis(x,1)<idis(x,1)<i,定义 fa(x,i)=0fa(x,i)=0

对于上图,fa(x,0)=xfa(x,0)=xfa(x,1)=y1fa(x,1)=y_1fa(x,2)=y2fa(x,2)=y_2fa(x,3)=y3fa(x,3)=y_3

考虑在节点 xx 放置一个爆炸范围 w=3w=3 的炸弹,分析这个炸弹所造成的影响:

  • 首先以节点 xx 为根的子树中,与节点 xx 距离不超过 33 的节点都会被炸一次,如上图中红色部分;
  • 以节点 y1y_1 为根的子树中,与节点 y1y_1 距离不超过 22且不在以节点 xx 为根的子树中的节点都会被炸一次,如上图中蓝色部分;
  • 以节点 y2y_2 为根的子树中,与节点 y2y_2 距离不超过 11且不在以节点 y1y_1 为根的子树中的节点都会被炸一次,如上图中绿色部分;
  • 节点 y3y_3 会被炸一次,如上图中黄色部分;

定义 f[x][i]f[x][i] 表示以节点 xx 为根的子树中,与节点 xx 距离不超过 ii 的节点都会被炸一次。

先处理炸弹,对于炸弹 ii

  • 以节点 pip_i 为根的子树中,与节点 pip_i 距离不超过 wiw_i 的节点都会被炸一次,即 dp[pi][wi]+=1dp[p_i][w_i]+=1
  • 枚举 0<j<wi0< j< w_i,如果 fa(pi,j)0fa(p_i,j)\neq 0,那么以节点 fa(pi,j)fa(p_i,j) 为根的子树中,与节点 fa(pi,j)fa(p_i,j) 距离不超过 wijw_i-j且不在以节点 fa(pi,j1)fa(p_i,j-1) 为根的子树中的节点都会被炸一次:
    • 先让以节点 fa(pi,j)fa(p_i,j) 为根的子树中,与节点 fa(pi,j)fa(p_i,j) 距离不超过 wijw_i−j 的节点都被炸一次,即 dp[fa(pi,j)][wij]+=1dp[fa(p_i,j)][w_i-j]+=1
    • 对于涉及到的以节点 fa(pi,j1)fa(p_i,j-1) 为根的子树中的节点,用树上差分的技巧进行抵消:令以节点 fa(pi,j1)fa(p_i,j-1) 为根的子树中,与节点 fa(pi,j1)fa(p_i,j-1) 距离不超过 wi(j+1)w_i-(j+1) 的节点都少被炸一次,即 dp[fa(pi,j1)][wi(j+1)]=1dp[fa(p_i,j-1)][w_i-(j+1)]-=1
  • 如果 fa(pi,wi)0fa(p_i,w_i)\neq 0,那么节点 fa(pi,wi)fa(p_i,w_i) 会被炸一次,即 dp[fa(pi,wi)][0]+=1dp[fa(p_i,w_i)][0]+=1

处理完所有炸弹后,从节点 11 出发进行 DFS\text{DFS},遍历一次整棵树。遍历的过程中维护 f[x][i]+=f[fa(x,1)][i+1]f[x][i]+=f[fa(x,1)][i+1]

完成遍历后,节点 ii 的答案 ans[i]=f[i][j]ans[i]=\sum f[i][j]

时间复杂度 O(50(m+n))O(50(m+n))

0 comments

No comments so far...