题目链接
https://www.nowcoder.com/acm/contest/145/C
题目描述
A binary string s of length $N = 2^n$ is given. You will perform the following operation n times :
- Choose one of the operators AND (&), OR (|) or XOR (^). Suppose the current string is $S = s_1s_2 \dots s_k$.
- Then, for all $1 \leq i \leq \frac{k}{2}$, replace $s_{2i-1}s_{2i}$ with the result obtained by applying the operator to $s_{2i-1}$ and $s_{2i}$.
For example, if we apply XOR to ${1101}$ we get ${01}$.
After n operations, the string will have length 1.
There are 3n ways to choose the n operations in total. How many of these ways will give 1 as the only character of the final string.
输入描述:
The first line of input contains a single integer n (1 ≤ n ≤ 18).
The next line of input contains a single binary string s $(|s| = 2^n)$. All characters of s are either 0 or 1.
输出描述:
Output a single integer, the answer to the problem.
题意
给你一个长度为$2^n$的$01$串,每次你可以从^
、&
、|
中选择一个操作符$op$,对这个串$S$进行一次运算(下标从0开始):$s_i = s_{2i}\ _{op}\ s_{2i+1}\ (0 \leq 2i < |S|)$,每运算一次之后$|S|_{new} = \frac{|S|_{old}}{2}$。
问有多少种方案可以使得$S$最后只剩下一个$1$。
思路
算了一下如果暴力搜索的话那么极限数据的状态集的大小约为$3^{18}=387420489$,显然不行。发现如果长度为$2$的时候,只要是包含$1$的串就一定会对答案产生贡献$2$,这样状态集的大小就减少为$3^{17}=129140163$,显然,可以再多递推几层,最优情况下状态集的大小为$3^9 \times 2=39366$,复杂度不要太优。
其实没那么麻烦,这道题完全可以$3^{17}$配合剪枝莽过去,然而我比赛的时候居然不会,还是自己太垃圾了。
实现
#include <bits/stdc++.h>
int status[20][1 << 20], ans, n;
char str[1 << 20];
int operation(int op, int x, int y) {
return op == 0 ? (x ^ y) : (op == 1 ? (x & y) : (x | y));
}
void dfs(int cur) {
for (int k = 0, upperK = (1 << cur + 1); k < upperK; k++) {
if (status[cur + 1][k]) {
if (cur)
for (int op = 0; op < 3; op++) {
for (int i = 0, upper = (1 << cur); i < upper; i++)
status[cur][i] = operation(op, status[cur + 1][i << 1], status[cur + 1][i << 1 | 1]);
dfs(cur - 1);
}
else ans += 2;
return ;
}
}
}
int main() {
scanf("%d%s", &n, str);
for (int i = 0; i < (1 << n); i++) status[n][i] = str[i] ^ '0';
dfs(n - 1);
printf("%d\n", ans);
return 0;
}