高维前缀和

高维前缀和

主要内容

昨天(\(\texttt{2022.2.28}\))打 ARC 的 D 题时,恍然发现我不会高维前缀和,匆匆来学一下。

比如二维前缀和 \(s_{i,j}\) 表示在一个二维平面上从 \((1,1)\) 到 \((i,j)\) 的所有点的权值之和,我们定义高维前缀和 \(s_{p_1,p_2,p_3,\cdots,p_n}\) 表示所有 \((q_1,q_2,q_3,\cdots,q_n)\) 并且满足 \(q_1\le p_1,q_2\le p_2,\cdots,q_n\le p_n\) 的所有点的权值之和。

如何求解高维前缀和呢?

举个例子,二维前缀和可以用一下代码来求:

for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	 	 sum[i][j]+=sum[i-1][j];
for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	 	 sum[i][j]+=sum[i][j-1];

类比一下,高维前缀和可以用如下方式求解:

// 假设前缀和是 q 进制的。 
int val[N]={1,q,q^2,q^3,...,q^{N-1}};
for(int opt=1;opt<=N;opt++)
	 for(int i=0;i<=MAX;i++)
	 	 if((i/val[opt])%q>=1)
	 	 	 sum[i]+=sum[i-val[opt]];

每一位都从这一位减一转移过来,其实高维前缀和也可以被想为一个 Dp 的过程,类似 Dp 的转移更好理解。

例题

CF772D Varying Kibibits

定义 \(f(S)\) 表示一个由若干个数组成的集合 \(S\) 中,返回值十进制每一位上的数为所有数中这一位的最小值。

给定 \(n\) 个数组成的集合 \(T\),求:

\[\oplus_{x=0}^{999999}\left(x\times\left(\left(\sum_{S\subseteq T,S\not=\emptyset,f(S)=x}\left(\sum_{y\in S}y\right)^2\right)\bmod 1000000007\right)\right) \]

\(n\le 10^6,t_i< 10^6\)。

想到高维前缀和之后,难点就是怎样从当前这一位比它大 \(1\) 的位置转移过来。

主要问题是平方和的合并问题,发现其实就是这样一个过程:

\[a_1^2+a_2^2~\texttt{add}~b_1^2+b_2^2+b_3^2\Rightarrow(a_1+b_1)^2+(a_1+b_2)^2+(a_1+b_3)^2+(a_1+b_1)^2+(a_2+b_2)^2+(a_2+b_3)^2 \]

这样好办了,在每一位记下所有集合的 \(sum\) 的和、所有集合的 \(sum^2\) 的和与集合数量,直接转移即可。

发现这样求出来的是 \(f(x)\) 大于等于它的答案,所以最后还要进行一次差分。

上一篇:Execution Plan 执行计划介绍


下一篇:递归(一)二叉树的最近公共祖先