2023年5月上海月赛甲组T1子集和(六)题解
标签搜索

2023年5月上海月赛甲组T1子集和(六)题解

tang01
2023-06-02 / 0 评论 / 281 阅读 / 正在检测是否收录...

题目描述

给定一个长度为 n 的序列 $a_1,a_2,a_3,...,a_n$ 与一个参数 $k$ 。

现有 $q$ 次询问,每次询问一个区间$[L,R]$,请你求出该区间内所有子集和中,有多少个子集和恰好是 $k$ 的倍数,答案对$998244353$取模。(注意:所有子集中包含空集)

算法思路

本题采用优雅的暴力结构——分块。

预处理

将序列分成$M=\sqrt{n}$块,每块分别记录三类数据$lr[M][M][20],rr[M][M][20],br[M][20]$。

$lr[i][j][r]$表示第$i$块,从块内倒数第$1$个数到正数第$j$个数所有组合中余数为$r$的个数,共$M$个块,每块需要$O(Mk)$,合计$O(nk)$。

$rr[i][j][r]$表示第$i$块,从块内正数第$1$个数到正数第$j$个数所有组合中余数为$r$的个数,共$M$个块,每块需要$O(Mk)$,合计$O(nk)$。

$br[i][r]$表示第$i$块,从头至尾所有组合中余数为$r$的个数,可以复用$rr[i][M][r]$。

注意根据乘法原理,例如余数2的个数*余数3的个数就是增加的余数5的个数。 我们可以$O(k^2)$来合并两个区间。
为了加快查询速度,我们再预处理一类数据$ss[M][M][20]$,$ss[i][j][r]$表示从第i块到第j块所有组合中余数为$r$的个数。

在求解 $ss[i][j]$ 时我们可以利用$ss[i][j-1]$ 和$br[j]$ 合并来得到,共有$M^2$块需要合并。
至此,我们预处理完毕,预处理时间复杂度$O(nk + nk^2)$。

查询

查询可以分三类。

  1. 若$l,r$在同一块内,则直接暴力计算即可,$O(Mk)$。
  2. 若分散$l,r$分散在两个相邻的块,假设 $l$ 在 $i$ 块,第 $s$ 个位置,$r$ 在 $j$ 块第 $t$ 个位置,直接$O(k)$快速合并$lr[i][s]$与$rr[j][t]$记录的余数个数信息,最终答案只需统计余数为0个数,故$O(k)$。
  3. $l,r$相距较远。同样假设 $l$ 在 $i$ 块,第 $s$ 个位置, $r$ 在 $j$ 块第 $t$ 个位置。现合并$lr[i][s]$与$rr[j][t]$记录的余数个数信息$O(k^2)$,再将合并结果与$ss[i+1][j-1]$记录的余数个数信息合并$O(k)$。

对于查询来说,第3类查询数量最多,因此单次查询复杂度可认定为$O(k^2)$。

总体时间复杂度

$O(nk^2+qk^2)$即$O((n+q)k^2)$

类似数据结构 猫树

猫树,一种改版线段树。思想和我的这种分块方式类似,所以我管我搞出来的这个分块叫做猫块。

3

评论 (0)

取消