牛客网暑期ACM多校训练营(第七场)C Bit Compression (dfs暴力解决)

本文介绍了一道关于位运算的编程题目,通过递归深度优先搜索(DFS)的方法来解决给定二进制字符串在特定操作下得到指定结果的方案数量问题。详细解析了两种不同的实现思路及代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://www.nowcoder.com/acm/contest/145/C

 

C、Bit Compression | 时间限制:2秒 | 内存限制:256M
A binary string s of length N = 2n 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 = s1s2...sk. Then, for all , replace s2i-1s2iwith the result obtained by applying the operator to s2i-1 and s2i. 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| = 2n). All characters of s are either 0 or 1.

输出描述:

Output a single integer, the answer to the problem.

示例1

输入

2
1001

输出

4

说明

The sequences (XOR, OR), (XOR, AND), (OR, OR), (OR, AND) works.

 

题意:给一串01字符,每次选择一种位运算符(& , | , ^ ) 在相邻的两个字符进行位运算,一直到最后剩下唯一的字符,问:有多少种方案,能使最后留下来的字符为 '1'

 

题解:这道题在比赛中怎么也没想到可以暴力解决,还是我太嫩了,没经过这些大风大浪。话不多说,直接dfs搞定:

直接上代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn=(1<<19); ///这里一定要开够(1<<18)的两倍,不然会出现数组越界的问题
///原因看下面
int A[maxn];
char op[maxn];
LL sum=0;

void dfs(int *B,int *P,int len) ///指针传参,变量名不同的同类事物
{
    bool flag=false;

    for(int i=1;i<=len;i++)
    if(P[i]==1) {
        flag=true;break;
    }

    if(!flag) return; ///全为0,不管怎么操作,最终都是为0

    if(len==1){  ///能到这一步,表示P[1]肯定为1,不然早返回了
        sum++;
    }

    for(int i=1,j=1;i<=len;i+=2,j++)
        B[j]=P[i]^P[i+1];
    dfs(B+(len>>1)+1,B,len>>1); ///传给下一层B数组的都是无关紧要的范围,而传给P数组的是要进行位运算的范围

    for(int i=1,j=1;i<=len;i+=2,j++)
        B[j]=P[i]|P[i+1];
    dfs(B+(len>>1)+1,B,len>>1);

    for(int i=1,j=1;i<=len;i+=2,j++)
        B[j]=P[i]&P[i+1];
    dfs(B+(len>>1)+1,B,len>>1);

    return;


}
int main()
{
    int n;
    while(~scanf("%d",&n)){
            sum=0;
    cin>>op;

    for(int i=0;op[i]!='\0';i++) ///字符转化为数字
        A[i+1]=op[i]-'0';

    dfs(A+(1<<n)+1,A,1<<n);
     ///把(1<<18)之后的空间给B,将(0到1<<18)的元素给P(这也解释了为什么要开(1<<18)(最大)的两倍了)
    ///因为在dfs中,每次都是拿P数组去位运算,拿B数组保存,要是也把(0到1<<18)的元素给B
    ///那么到时会发生混乱,因为一个堆栈里有3个dfs,倘若这样,将会改变初始化的P数组元素值,
    ///因为传参的是指针类型的,传过去只是变量名不同的同类事物
    
    
    
    
    printf("%lld\n",sum);

    }

    return 0;
}

 

再贴一份网上的代码,觉得挺有意思的,所以就贴上来:

#include<bits/stdc++.h>
using namespace std;
char ch[20][(1<<18)+5];
int ans;
char op(char x,char y,int xx)
{
    if(xx==1)return (int)((x-'0')^(y-'0'))+'0';
    if(xx==2)return (int)((x-'0')&(y-'0'))+'0';
    return (int)((x-'0')|(y-'0'))+'0';
}
void dfs(char *s,int n)
{
    for(int j=1;j<=3;j++)
    {
        int cnt=0;
        for(int i=0;i<(1<<n);i+=2)
        {
            ch[n-1][i>>1]=op(s[i],s[i+1],j);
            if(ch[n-1][i>>1]=='1') cnt++; ///计数有多少位是1
        }
        if(cnt==(1<<(n-1))) ans+=cnt; ///表示全1

///这里表示,全部为1时,有多少个1就有多少个方案,为什么呢?
///例如剩下1 1,只能在 | &中挑一个,那就2种了
///1 1 1 1 ,两次操作使得最后为1,每次选| 或者&,那就2^2=4了
///有2^n个1,表示要操作n次才能使最后字符剩一个,每次只能用这两种 | &,那即是有 2^n种方案了
///全1不能用^ 这操作符,一用最终一定变为0


        else if(cnt!=0) dfs(ch[n-1],n-1);
    }
}
int main()
{
    int n;
    cin>>n;
    scanf("%s",ch[n]);
    dfs(ch[n],n);
    cout<<ans<<endl;
    return 0;
}

 

 

我的标签:做个有情怀的程序员。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值