题目链接

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;
}
最后修改:2018 年 08 月 10 日
谢谢老板!