集合幂级数

算法

\(c_k\ =\ \sum_{i,\ j}\ [i\ or\ j\ =\ k]\ [i\ and\ j\ =\ 0]\ a_i\ b_j\)
考虑 \(c_k\ =\ \sum_{i,\ j}\ [i\ or\ j\ =\ k]\ a_i\ b_j\),反演后得到 \(A_{0,\ 1,\ ...,\ n\ -\ 1},\ B_{0,\ 1,\ ...,\ n\ -\ 1}\)
类似的,将 \(a_i\) 写成多项式的形式 \(a_i(x)\ =\ \sum_{j\ =\ 0}^{log2(n)}\ [j\ =\ bit(i)]\ a_i\ x^i\)\(A,\ B\) 为对 \(a,\ b\) 反演得到的多项式,\(c_i\ =\ [x^{bit(i)}]\ c_i(x)\) 即可,其中 \(bit(i)\) 为c++中 __builtin_popcount(i)。

应用

代码

FMT

FMT

const int maxn = (1 << 19) | 10, maxm = 20, mod = 998244353; // deal with n <= 2**19

namespace FMT {
	const unsigned long long LIM = 17e18, MOD = LIM / (unsigned long long) mod * (unsigned long long) mod;
	int n, m, A[maxn][maxm], B[maxn][maxm], C[maxn][maxm];

	void upd(int &x, const int &y) { x += y; if(x >= mod) x -= mod; return; }

	void trans(int f[maxn][maxm]) {
		for (int hl = 1, l = 2; l <= n; hl = l, l <<= 1) for (int i = 0; i < n; i += l) for (int j = 0; j < hl; ++j) for (int k = 0; k <= m; ++k) upd(f[i + j + hl][k], f[i + j][k]);
		return;
	}

	void itrans(int f[maxn][maxm]) {
		for (int hl = 1, l = 2; l <= n; hl = l, l <<= 1) for (int i = 0; i < n; i += l) for (int j = 0; j < hl; ++j) for (int k = 0; k <= m; ++k) upd(f[i + j + hl][k], mod - f[i + j][k]);
		return;
	}

	void mul(int *a, int *b, int *c) {
		for (int i = 0; i <= m; ++i) {
			unsigned long long t = 0;
			for (int j = 0; j <= i; ++j) {
				t += (unsigned long long) a[i - j] * b[j];
				if(t >= LIM) t -= MOD;
			}
			c[i] = t % mod;
		}
		return;
	}

	void work(int _n, int *a, int *b, int *c) {
		n = _n; m = 0; while((1 << m) < n) ++m;
		if(m <= 3) {
			memset(c, 0, sizeof(c[0]) * n);
			for (int i = 0; i < n; ++i) for (int x = a[i], t = (n - 1 ^ i), j = t; ; j = (j - 1 & t)) {
				c[i | j] = ((long long) x * b[j] + c[i | j]) % mod;
				if(!j) break;
			}
			return;
		}
		for (int i = 0; i < n; ++i) memset(A[i], 0, sizeof(A[i][0]) * (m + 1)), A[i][__builtin_popcount(i)] = (a[i] + mod) % mod; trans(A);
		for (int i = 0; i < n; ++i) memset(B[i], 0, sizeof(B[i][0]) * (m + 1)), B[i][__builtin_popcount(i)] = (b[i] + mod) % mod; trans(B);
		for (int i = 0; i < n; ++i) mul(A[i], B[i], C[i]);
		itrans(C); for(int i = 0; i < n; ++i) c[i] = C[i][__builtin_popcount(i)];
		return;
	}
}
posted @ 2018-07-12 11:35  King_George  阅读(399)  评论(0编辑  收藏  举报