题目链接: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;
}
我的标签:做个有情怀的程序员。