T1

100%

读入字符串 SS,用循环语句枚举字符串 SS 的第 ii 位,如果 SSi,i+1,i+2i,i+1,i+2 这三位恰好是 wow,那么答案加一。

注意 ii 的循环范围,要避免 i+2i+2 越界,同时注意字符串的下标是从 00 还是从 11 开始。

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

T2

100%

0n0\sim n 共有 n+1n+1 个数字,其中至少有一个数字没在 AA 中出现。所以 AAMEX\text{MEX} 不超过 nn

这意味着我们只需要考虑 AinA_i\leq n 的情况。

先循环第一次遍历 AA,对于所有满足 AinA_i\leq n 的元素,用数组 BB 标记它在 AA 中是否出现过。B[x]=1B[x]=1 表示 xxAA 中出现过,B[x]=0B[x]=0 表示 xxAA 中没有出现过。

再循环第二次遍历 BB,答案即为最小的满足 B[x]=0B[x]=0xx

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

T3

50%

用一个二维数组 f[i][j]f[i][j] 记录 iijj 是否有矛盾。

两重循环模拟分班过程:外层循环按从 11nn 的顺序枚举第 xx 个人,内层循环枚举在 xx 之前已经完成分班的 yy,如果 xxyy 有矛盾,那么 xx 不能分到 yy 所在的班。可以用 22 个变量分别表示 xx 能否分到1班和2班,按题目所说的规则决定 xx 去哪个班并记录下来用于后续判断,同时维护两个班的总团结度变化。

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

100%

在第一部分的基础上,用邻接表代替二维数组:vec[i]vec[i] 中记录和 ii 有矛盾且在 ii 之前完成分班的人。

在模拟分班的过程中,当外层循环枚举到第 xx 个人分班时,内层循环改为枚举 vec[x]vec[x] 中的元素。

由于每条矛盾关系只会让 vec[max(ui,vi)]vec[\max(u_i,v_i)] 增加一个元素,所以 nnvector\text{vector} 内一共有 mm 个元素,空间复杂度 O(n+m)O(n+m)

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

T4

20%

暴力计算出矩阵 CC 中每个数字,对其排序后求出区间和。

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

40%

对于测试点#3~4,因为 Ai,Bi2000A_i,B_i\leq 2000,所以 C(i,j)4×106C(i,j)\leq 4\times 10^6

用数组 cntA[x]cntA[x] 记录数字 xxAA 中出现了多少次,数组 cntB[x]cntB[x] 记录数字 xxBB 中出现了多少次。

可以维护出表示数字 xxCC 中出现了多少次的数组 cntC[x]cntC[x]:枚举 iijjcntC[i×j]cntC[i\times j] 增加 cntA[i]×cntB[j]cntA[i]\times cntB[j]

定义 ask(k)ask(k) 表示前 kk 小的数字的和,将区间和转化为两个前缀和的差分,答案即为 ask(R)ask(L1)ask(R)-ask(L-1)

ask(k)ask(k) 可以通过循环遍历 cntCcntC 来计算。

AiA_i 的最大值为 VA=max{Ai}V_A=\max\{A_i\}BiB_i 的最大值为 VB=max{Bi}V_B=\max\{B_i\}

时间复杂度 O(VAVB)O(V_AV_B)

结合第一部分可以拿到 40%40\% 的分数。

60%

对于测试点#5~6,因为 L=1L=1,所以答案就是 ask(R)ask(R)。我们只需要考虑如何计算 ask(R)ask(R)

记矩阵 CC 中,满足 C(i,j)xC(i,j)\leq x 的元素数量为 num(x)num(x),满足 C(i,j)xC(i,j)\leq x 的元素之和为 sum(x)sum(x)

num(x)num(x) 可以用二分来计算:

  • 先将 BB 按从小到大的顺序排序;
  • 枚举 AA 的下标 ii,二分求出满足 Ai×BjxA_i\times B_j \leq x 的最大的 jj,将 jj 加到返回值中。

用上述方法求一次 num(x)num(x) 的时间复杂度为 O(nlog(m))O(n\log(m))

sum(x)sum(x) 的方法类似求 num(x)num(x) 的方法:

  • 先将 BB 都按从小到大的顺序排序,处理出排序后 BB 的前缀和 Bsum[i]Bsum[i]
  • 枚举 AA 的下标 ii,二分求出满足 Ai×BjxA_i\times B_j \leq x 的最大的 jj,将 $A[i]\times B[1]+A[i]\times B[2]+\dots+A[i]\times B[j]=A[i]\times(B[1]+B[2]+\dots+B[j])=A[i]\times Bsum[j]$ 加到返回值中。

这样就可以二分求满足 num(val)Rnum(val)\geq R 的最小的 valval,这个 valval 也就是第 RR 小的那一项的值。

求出 valval 之后,sum(val)sum(val) 即为前 num(val)num(val) 小的数字的和。对于 num(val)>Rnum(val)>R 的情况,因为第 RR 小和第 num(val)num(val) 小的数字都等于 valval,所以第 R+1R+1 小到 num(val)num(val) 小的数字都等于 valval,减去这部分即可。

答案 ask(R)=sum(val)val×(num(val)R)ask(R)=sum(val)-val\times (num(val)-R)

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

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

100%

在第三部分的基础上,将区间和转化为两个前缀和的差分,答案即为 ask(R)ask(L1)ask(R)-ask(L-1)

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

T5

40%

枚举 pp,以 pp 为起点 DFS\text{DFS} 整棵树,过程中维护到每个节点的距离,计算答案。

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

60%

p=ip=i 时的答案为 ansp=i=1nai×dis(p,i)ans_p=\sum_{i=1}^na_i\times \text{dis}(p,i)

对于测试点#5~6,因为 ai=1a_i=1li=1l_i=1,所以答案就是每个节点到 pp 的距离之和。

将树看成以 11 为根的有根树,用 siz[i]siz[i] 表示以 ii 为根的子树内的节点数量。考虑 ansyans_yansxans_x 的关系,这里节点 xx 是节点 yy 的父节点,如下图所示:

题解p1

考虑 ppxx 变成 yy,那么图中红色的节点到 pp 的距离增加 11,绿色的节点到 pp 的距离减少 11。绿色的节点即是以节点 yy 为根的子树内的节点,数量为 siz[y]siz[y];红色的节点数量为 nsiz[y]n-siz[y]。因此 ansy=ansx+(nsiz[y])siz[y]ans_y=ans_x+(n-siz[y])-siz[y]

因此只需要先从节点 11 出发用 DFS\text{DFS} 计算出 ans1ans_1 以及 siz[i]siz[i] 数组,然后再进行第二次 DFS\text{DFS},计算出其他节点的答案。

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

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

100%

考虑 ppxx 变成 yy,红色节点到 pp 的距离增加 dis(x,y)dis(x,y),绿色的节点到 pp 的距离减少 dis(x,y)dis(x,y)

sum[i]sum[i] 表示以 ii 为根的子树内的节点的权值之和,绿色节点总权值为 sum[y]sum[y],红色节点总权值为 sum[1]sum[y]sum[1]-sum[y]

因此在第二次 DFS\text{DFS} 时,用 $ans_y=ans_x+dis(x,y)\times (sum[1]-sum[y])-dis(x,y)\times sum[y]$ 计算其他节点的答案即可。

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

T6

20%

ans[i]ans[i] 表示 ii 对应的答案。

预先处理出数组 pcnt[i]=popcount(Ai)pcnt[i]=\text{popcount}(A_i)

两重循环枚举 iijj,枚举时注意 iji\leq j,判断是否满足 AiAj>XA_i\oplus A_j>Xpcnt[i]pcnt[j]pcnt[i]\leq pcnt[j],如果都满足则 ans[i]ans[i] 增加 11

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

时间复杂度 O(nlog(V)+n2)O(n\log(V)+n^2)

50%

对于测试点#3~5,因为 X,Ai1000X,A_i\leq 1000,可以直接预处理 bool\text{bool} 数组 f[Y][Z]f[Y][Z],其中 f[Y][Z]=1f[Y][Z]=1 表示 YYZZ 满足 YZ>XY\oplus Z>Xpopcount(Y)popcount(Z)\text{popcount}(Y)\leq \text{popcount}(Z),题目的三个条件就转化为 jij\geq if[Ai][Aj]=1f[A_i][A_j]=1

从大到小枚举 ii,同时维护 cnt[x]cnt[x] 表示 xx 已经出现了多少次,对于每一个满足 f[Ai][x]=1f[A_i][x]=1xxans[i]ans[i] 增加 cnt[x]cnt[x]

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

结合第一部分可以拿到 50%50\% 的分数。

100%

先不考虑 pcnt[i]pcnt[j]pcnt[i]\leq pcnt[j] 这一条件,仅考虑余下两个条件,可以用 01trie\text{01trie} 来解决,将满足 ijni\leq j\leq n 的每个 AjA_j 都添加到字典树上后,ans[i]ans[i] 可以在字典树上查询。

在此基础上考虑 pcnt[i]pcnt[j]pcnt[i]\leq pcnt[j] 这一条件,有以下两个方法:

  • 方法1

开一个二维数组 siz[j][k]siz[j][k],记录字典树上节点 jj 对应的子树内,满足 pcnt[i]=kpcnt[i]=kii 的数量。

查询 ans[i]ans[i] 时,每当在字典树上走到节点 jj,枚举 kk 满足 kpcnt[i]k\geq pcnt[i],将 siz[j][k]siz[j][k] 加到答案中。

二维数组 sizsiz 的第一维如果开到 n×log(V)n\times \log(V) 有可能会空间超限,可以证明第一维只需开到 n×15n\times 15 以上就足够了:字典树上对应二进制最高 1616 位的节点不超过 216+1n2^{16+1}\leq n 个点,剩余节点不超过 n×(log(V)16)n\times (\log(V)-16) 个,而 log(V)30\log(V)\leq 30,所以最多不超过 n×15n\times 15 个点。

时间复杂度 O(nlog2(V))O(n\log^2(V))

  • 方法2

log(V)\log(V) 轮计算答案,第 kk 轮只对满足 popcount(Ai)=k\text{popcount}(A_i)=kii 求答案,所以第 kk 轮只将同时满足 popcount(Aj)k\text{popcount}(A_j)\geq kjij\geq iAjA_j 添加到字典树上。

时间复杂度 O(nlog2(V))O(n\log^2(V))

0 comments

No comments so far...