← 全部文章

CF582E Boolean Function 题解

本文目录(3 节)
  1. 题意
  2. 题解
  3. 代码

CF582E Boolean Function

题意

  • A,B,C,D,a,b,c,d 为八个布尔「变量」,其中小写字母的值等于对应大写字母的值取反。
  • &,| 为两个布尔「操作符」。
  • 布尔「表达式」为一个「变量」,或通过「操作符」连接起来的两个「表达式」。
  • 布尔「函数」f(A,B,C,D) 为一个布尔「表达式」。
  • 给定一个可能缺少某些「变量」和「操作符」(用 ? 代替)的「函数」s,并给出 nn 个函数在 A,B,C,D 确定时的值。
  • 求可能的「函数」个数。
  • ∣s∣≤500|\texttt{s}|\le 500,n≤16n \le 16,答案对 109+710^9+7 取模。

题解

先建出表达式树,设 f[i][j]f[i][j] 表示树中点 ii 处将 nn 个值压缩成 jj 的方案数。

对于一个非叶节点 ii 转移为 f[i][x]=∑x=y⊕zf[j][y]×f[k][z] f[i][x] = \sum_{x = y \oplus z} f[j][y] \times f[k][z] 因此可以 FWT 优化,总时间复杂度 O(∣s∣n2n)\mathcal O(|\texttt{s}|n2^n)。

代码

const int N = 507, M = 16;
int k, n, m, fa[N], t = 1, p = 1;
char s[N], c[N];
int h[M|1][5];
vi e[N];
modint f[N][1<<M|1], a[1<<M|1], b[1<<M|1];

inline void in(modint *A, modint *B) {
	for (int i = 0; i < n; i++) a[i] = A[i], b[i] = B[i];
}

inline void get() {
	for (int i = 0; i < n; i++) a[i] *= b[i];
}

inline void out(modint *f) {
	for (int i = 0; i < n; i++) f[i] += a[i];
}

inline void OR(modint *f, modint x = 1) {
	for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
		for (int i = 0; i < n; i += o)
			for (int j = 0; j < k; j++)
				f[i+j+k] += f[i+j] * x;
}

inline void AND(modint *f, modint x = 1) {
	for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1)
		for (int i = 0; i < n; i += o)
			for (int j = 0; j < k; j++)
				f[i+j] += f[i+j+k] * x;
}

void dfs(int x) {
	if (!e[x].size()) {
		if (c[x] == '?')
			for (int i = 0; i < 4; i++) {
				int k = 0;
				for (int j = 0; j < m; j++) k |= h[j][i] << j;
				f[x][k] += 1, f[x][((1<<m)-1)^k] += 1;
			}
		else {
			int i = c[x] - (c[x] >= 'A' && c[x] <= 'D' ? 'A' : 'a'), k = 0;
			for (int j = 0; j < m; j++) k |= h[j][i] << j;
			f[x][c[x]>='A'&&c[x]<='D'?k:(((1<<m)-1)^k)] += 1;
		}
		return;
	}
	dfs(e[x][0]);
	dfs(e[x][1]);
	if (c[x] != '&') in(f[e[x][0]], f[e[x][1]]), OR(a), OR(b), get(), OR(a, P - 1), out(f[x]);
	if (c[x] != '|') in(f[e[x][0]], f[e[x][1]]), AND(a), AND(b), get(), AND(a, P - 1), out(f[x]);
}

int main() {
	rds(s, k), rd(m), n = 1 << m;
	for (int i = 1; i <= k; i++)
		if (s[i] == '(') e[p].pb(++t), fa[t] = p, p = t;
		else if (s[i] == ')') p = fa[p];
		else c[p] = s[i];
	for (int i = 0; i < m; i++)
		for (int j = 0; j < 5; j++)
			rd(h[i][j]);
	dfs(1);
	int o = 0;
	for (int i = 0; i < m; i++) o |= h[i][4] << i;
	print(f[1][o]);
	return 0;
}

标签:DP、FWT、树形 DP

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…