我們知道一維前綴和是可以這么求的:
for (int i = 1; i <= n; ++i) a[i] += a[i - 1];
而一維前綴和是可以這么求的:
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1];
這是基於容斥的做法
當然我們也可以一維一維的去累計:
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
a[i][j] += a[i][j - 1]; //累計了每一行的前綴和
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
a[i][j] += a[i - 1][j];//累計了每一列的前綴和
容易看出,當數組的位數變高的時候,如果我們要基於容斥去計算數組前綴和,容斥的項數越來越多,寫起來也更加復雜,而如果我們按照維數去統計,則會有比較好的效果.
比如,給出$a[i]$ ,對於每一個$i$,求出$\sum_{j \& i = j} a[j]$
這道題其實是讓我們求出某個數二進制狀態下的子集和,如果我們對於每一個數去枚舉子集復雜度是$3n$的,其中$n$為二進制位數,但是,如果我們把一個數看成一個$n$維空間,那么題目中要求的其實就是一個$n$維的前綴和,我們仿照上面的形式,一維一維的掃過去求和即可,復雜度$O(n*2n)$.
for (int i = 0; i < n; ++i) //遍歷每一維
for (int j = 0; j < (1 << n); ++j)
if ((j >> i) & 1) a[j] += a[j ^ (1 << i)]; //做前綴和