题解:
然后就是接下来如何fwt
也就是如何处理bit(x) - bit(y) = bit(k)这个条件。
其实就是子集卷积。
把bit(x)和bit(y)划分成两个集合,然后就是子集卷积的形式。
这里设两个新的数组 A[bit(y)][y], B[bit(x)][x],代表拆出来的相应数组
然后对这两个数组做fwt,得到其点值表示,然后直接在外层枚举x和y的大小然后做卷积即可。
这样说可能很抽象,其实贴出代码就很清楚了
#include#include #include using namespace std;const int MOD = 998244353;typedef long long LL;LL mypow(LL a, LL b){ LL ans = 1; for(; b; b >>= 1) { if(b&1) (ans *= a) %= MOD; (a *= a) %= MOD; } return ans;}LL I2 = mypow(2, MOD-2);const int maxn = (1<<19) + 100;LL a[maxn], b[maxn], A[21][maxn*4], B[21][maxn*4], C[21][maxn*4];vector Bit[21];int m;class FWT{public: void fwt(LL *a, int n){ for(int d = 1; d < n; d <<= 1){ for(int m = d<<1, i = 0; i < n; i += m){ for(int j = 0; j < d; j++){ LL x = a[i+j], y = a[i+j+d]; a[i+j] = x+y; if(a[i+j] >= MOD) a[i+j] -= MOD; a[i+j+d] = x-y; if(a[i+j+d] < 0) a[i+j+d] += MOD; } } } } void ufwt(LL *a, int n){ for(int d = 1; d < n; d <<= 1){ for(int m = d<<1, i = 0; i < n; i += m){ for(int j = 0; j < d; j++){ LL x = a[i+j], y = a[i+j+d]; a[i+j] = (x+y)*I2%MOD; a[i+j+d] = (x-y+MOD)*I2%MOD; } } } } void work(LL *a, LL *b, int n){ fwt(a, n); fwt(b, n); for(int i = 0; i < n; i++) a[i] *= b[i]; ufwt(a, n); }}myfwt;int bit(int x){ int ans = 0; for(int i = 0; i < 19; i++) ans += ((x&(1< 0); return ans;}int main(){ for(int i = 0; i < (1<<19); i++) Bit[bit(i)].push_back(i); cin>>m; for(int i = 0; i < (1< = L) break; A[i][x] = (a[x]*(1<