1. 程式人生 > 其它 >高維字首和

高維字首和

高維字首和

主要內容

昨天(\(\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)\) 大於等於它的答案,所以最後還要進行一次差分。