【CF1119H】Triple

【CF1119H】Triple

題面

洛谷

題解

有一個想法就是把每一個\(\{a_i,b_i,c_i\}\)寫成生成函數\(\text{F}_i\)然後 FWT 起來,再 IFWT 回去發現這樣是過不了的。
因爲有\(FWT(A\times B)=FWT(A)\times FWT(B)\)
所以 FWT 後所得的結果就是直接把每個 FWT 後再點積起來,即\(FWT(\prod \text F_k)=\prod FWT(\text F_k)[i]=\prod_{j=1}^n(-1)^{|a_j\&i|}x+(-1)^{|b_j\&i|}y+(-1)^{|c_j\&i|}z\),想辦法求出\(FWT\)數組。
因爲每個項都是\(x,y,z\)加減起來的,但是這樣子的話有\(8\)種結果,比較煩,考慮將每個三元組異或上\(a_i\),那麼找\(i\)最終答案的項數再異或上一個\(\oplus_i a_i\)即可,三元組就變爲\(\{0,a_i\oplus b_i,a_i\oplus c_i\}\)
那麼現在我們只有\(x+y+z,x+y-z,x-y+z,x-y-z\),想辦法將四種情況的數目求出來,設對於某個\(i\),四種情況的數目爲\(e,f,g,h\),那麼顯然有\(e+f+g+h=n\)

如果令\(\text F_k[b_k]=1\),其他項爲\(0\),相當於\(x=0,y=1,z=0\),那麼最終求出來的結果就是\(y\)前面的係數,即\(y\)係數爲正減去\(y\)係數爲負的情況,那麼有\(e+f-g-h=FWT(\sum\text F_k)[i]\)\(\sum \text F_k\)在括號裏是因爲\(FWT(A)+FWT(B)=FWT(A+B)\)

同理可以令\(\text F_k[c_k]=1,a_k=b_k=0\),其他項爲\(0\),相當於\(x=0,y=0,z=1\),那麼求的是\(z\)前面的係數,有\(e-f+g-h=FWT(\sum\text F_k)[i]\)

再令\(\text F_k[b_k\oplus c_k]=1\)其他爲\(0\),那麼就是求的兩個的卷積=點值點積即\(\text F_k[i]=(-1)^{|b_j\&i|}(-1)^{|c_j\&i|}\),也是同時考慮\(x,y\)前符號相同\(-\)不同,即\(e-f-g+h=FWT(\sum\text F_k)[i]\)

\(e,f,g,h\)解方程解出來就好了,實現細節詳見代碼。

代碼

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std; 
using LL = long long; 
const int Mod = 998244353, inv2 = (Mod + 1) >> 1; 
int fpow(int x, LL y) {
    int res = 1; 
    while (y) {
        if (y & 1) res = 1ll * res * x % Mod; 
        x = 1ll * x * x % Mod; 
        y >>= 1; 
    } 
    return res; 
} 
const int MAX_N = 1 << 17 | 1; 
int N, K, Limit; 
void FWT(LL p[]) { 
    for (int i = 1; i < Limit; i <<= 1) 
        for (int j = 0; j < Limit; j += i << 1) 
            for (int k = 0; k < i; k++) { 
                LL x = p[j + k], y = p[i + j + k]; 
                p[j + k] = x + y, p[i + j + k] = x - y; 
            } 
}
void IFWT(LL p[]) { 
    for (int i = 1; i < Limit; i <<= 1) 
        for (int j = 0; j < Limit; j += i << 1) 
            for (int k = 0; k < i; k++) { 
                LL x = p[j + k] % Mod, y = p[i + j + k] % Mod; 
    		p[j + k] = 1ll * (x + y) * inv2 % Mod, p[i + j + k] = 1ll * (x - y + Mod) * inv2 % Mod; 
            } 
} 
     
LL F[MAX_N], G[MAX_N], H[MAX_N], A[MAX_N];
int x, y, z; 
int sum;
LL s1, s2, s3, s4; 
     
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    scanf("%d %d %d %d %d", &N, &K, &x, &y, &z); Limit = 1 << K; 
    for (int i = 1; i <= N; i++) { 
        int a, b, c; scanf("%d %d %d", &a, &b, &c); 
        sum ^= a, ++F[a ^ b], ++G[a ^ c], ++H[b ^ c]; 
    } 
    s1 = 1ll * x + y + z, s2 = 1ll * x + y - z, s3 = 1ll * x - y + z, s4 = 1ll * x - y - z;
    s1 %= Mod, s2 %= Mod, s3 %= Mod, s4 %= Mod; 
    FWT(F), FWT(G), FWT(H); 
    for (int i = 0; i < Limit; i++) {
        LL e = (N + F[i] + G[i] + H[i]) >> 2; 
        LL f = (N + F[i] - 2 * e) >> 1; 
        LL g = (N + G[i] - 2 * e) >> 1;
        LL h = (N + H[i] - 2 * e) >> 1; 
        A[i] = 1ll * fpow(s1, e) * fpow(s2, f) % Mod * fpow(s3, g) % Mod * fpow(s4, h) % Mod; 
    } 
    IFWT(A); 
    for (int i = 0; i < Limit; i++) printf("%I64d ", (A[i ^ sum] + Mod) % Mod); 
    putchar('\n'); 
    return 0; 
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章