ABC367G 題解

CTHOOH發表於2024-08-23
題意

給定正整數 \(N, M, K\) 和一個非負整數序列 \(A = (A_1, A_2, \dots, A_N)\)

對於一個非空的序列 \(B = (B_1, B_2, \dots, B_{|B|})\),我們定義它的得分為:

  • \(|B|\)\(M\) 的倍數:\((B_1 \oplus B_2 \oplus \dots \oplus B_{|B|})^K\)
  • 否則為 \(0\)

這裡 \(\oplus\) 運算表示按位異或。

找到序列 \(A\)\(2^N - 1\) 個非空子序列的得分之和,對 \(998244353\) 取模。

首先考慮轉化這個 \(K\) 次方,發現對於異或和很難用組合方面的知識轉化,所以直接考慮對於每個 \(x\),求 \(f_x\) 表示有多少長度為 \(M\) 倍數的子序列異或和等於 \(x\)。總答案為 \(\sum\limits_{x} \left(f_x \times x^k\right)\),問題轉化為求出 \(f\) 陣列。

這個問題的形式很 \(\operatorname{FWT}\),更進一步,我們有 \(n\) 個冪級數 \(H_i\),第 \(i\) 個冪級數 \(\operatorname{FWT}\) 前只有 \(0\)\(A_i\) 的位置有值,因為有 \(M\) 的限制,所以我們考慮把它的係數變成一個矩陣 \(Y\),因為 \(\operatorname{FWT}\) 是一個線性變換,所以係數是整數還是矩陣都沒有影響。

將每個 \(H_i\) \(\operatorname{FWT}\) 一遍後得到 \(H_i'\),將其點乘起來並 \(\operatorname{IFWT}\) 一遍後就得到了 \(f_i\) 了,時間複雜度 \(O(n V \log V)\),其中 \(V\)\(A_i\) 的值域。

考慮最佳化上面這個做法,容易發現每個 \(H_i\) 中只有 \(A_i\)\(0\) 的位置有值,分別是 \(Y\)\(I\),其中 \(I\) 是單位矩陣。根據 \(\operatorname{xor}\) 運算的 \(\operatorname{FWT}\) 的性質,\(H_i' = \sum_j (-1)^{\operatorname{popcount}(i ~\&~ j)} H_j\),則可以發現 \(H_i'\) 只有兩種情況:\((I + Y)\)\((I - Y)\)。所以最後點乘後得到的 \(f_i'\) 一定為 \((I + Y)^a(I - Y)^b\),且 \(a + b = N\)

先用 \(O(NM)\)\(dp\) 預處理出矩陣的值(其實根本不用推出這個矩陣),只需要記 \(dp_1[i][j]\)\(dp_2[i][j]\),然後用下面的遞推式推導即可:

\[\begin{cases} dp_1[i + 1][j] = dp_1[i][j] + dp_1[i][(j - 1 + M) \bmod M] \\ dp_2[i + 1][j] = dp_2[i][j] - dp_2[i][(j - 1 + M) \bmod M] \end{cases} \]

再推一個 \(G_i = \sum\limits_{j = 0}^{M - 1}dp_1[i][j] \times dp_2[N - i][(M - j) \bmod M]\),這樣得到了 \((I + Y)^i(I - Y)^{N - i}\) 的值了。

接下來考慮快速得到這個 \(a\),根據 \(\operatorname{FWT}\) 的性質,如果 \(\operatorname{popcount}(x ~\&~ y)\) 為偶數,那麼 \(y\) 就給 \(f_x\) 貢獻了一個 \((I + Y)\)。所以計算 \(f_x\)\(a\),實際上是在計數有多少 \(A_i\) 使得 \(\operatorname{popcount}(A_i ~\&~ x)\) 為偶數。考慮使用 \(\operatorname{FWT}\) 加速這一過程,記 \(F_{i, j}\) 表示有多少 \(x\),使得 \(\operatorname{popcount}(i, x) \bmod 2 = j\),初始值 \(F_{x, 0} = cnt(x)\)(因為初始的時候相當於序列長度只有 \(1\)),其中 \(cnt(x) = \sum\limits_{i = 1}^N[x = A_i]\)

基於 \(\operatorname{FWT}\) 蝴蝶變換時的性質,當兩邊進行合併時剛好有 \(1\) 位不同,所以有轉移(記 \(x = j + k, y = i + j + k\),其中 \(i, j, k\) 為蝴蝶變換時的三個下標):

\[\begin{cases} F'_{x, 0} = F_{x, 0} + F_{y, 0} \\ F'_{x, 1} = F_{x, 1} + F_{y, 1} \\ F'_{y, 0} = F_{x, 0} + F_{y, 1} \\ F'_{y, 1} = F_{x, 1} + F_{y, 0} \end{cases} \]

最後將 \(f'_i \gets G_{F_{i, 0}}\) 即可,\(\operatorname{IFWT}\) 一遍就得到原來的 \(f_i\) 了,總時間複雜度 \(O(NM + V \log V)\)

程式碼是賀的,就不放了。