高維字首和
阿新 • • 發佈:2022-03-01
高維字首和
主要內容
昨天(\(\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)\) 大於等於它的答案,所以最後還要進行一次差分。