题解链接
http://www.lucien.ink/archives/314/
题目链接
https://www.nowcoder.com/acm/contest/145/C
题目描述
A binary string s of length is given. You will perform the following operation n times :
- Choose one of the operators AND (&), OR (|) or XOR (^). Suppose the current string is .
- Then, for all , replace with the result obtained by applying the operator to and .
For example, if we apply XOR to we get .
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 . All characters of s are either 0 or 1.
输出描述:
Output a single integer, the answer to the problem.
题意
给你一个长度为
的
串,每次你可以从^
、&
、|
中选择一个操作符
,对这个串
进行一次运算(下标从0开始):
,每运算一次之后
。
问有多少种方案可以使得 最后只剩下一个 。
思路
算了一下如果暴力搜索的话那么极限数据的状态集的大小约为 ,显然不行。发现如果长度为 的时候,只要是包含 的串就一定会对答案产生贡献 ,这样状态集的大小就减少为 ,显然,可以再多递推几层,最优情况下状态集的大小为 ,复杂度不要太优。
其实没那么麻烦,这道题完全可以 配合剪枝莽过去,然而我比赛的时候居然不会,还是自己太垃圾了。
实现
#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;
}