https://www.nowcoder.com/acm/contest/145/C
题意:给你一个n,再给你一个长度为2的n次方的01串。每次字符串可以选择三种操作:& | ^。选择之后,相邻的字符按这个操作合并:比如 1101 选择^ 则 1^1=0 0^1=1; 然后字符串就变成了01。继续操作直到剩余一个字符。问你最后只剩一个1的方法总数有多少种。
思路:
直接爆搜会TLE,注意剪枝,如果全为0的,这三种操作怎么操作都不可能是1,所以直接停止。
保存每次操作的答案可以模仿线段树一样,最底下的一层是原串,然后一层一层网上递归,最后判断根节点是否为1,这样就不会破坏原来的字符串了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+10;
char c[maxn];
int t[maxn*4];
int ans;
void dfs(int n)
{
if(n==-1)
{
if(t[1]==1)
{
ans++;
}
return;
}
int k=1<<n;
for(int i=0;i<3;i++)
{
int zz=0;
for(int j=0;j<k;j++)
{
int te=j+k;
if(i==0)
{
t[te]=t[te*2]|t[te*2+1];
}
if(i==1)
{
t[te]=t[te*2]^t[te*2+1];
}
if(i==2)
{
t[te]=t[te*2]&t[te*2+1];
}
if(!t[te])zz++;
}
if(zz==k)continue;
dfs(n-1);
}
}
int main()
{
int n;
scanf("%d",&n);
scanf("%s",c);
int k=1<<n;
for(int i=0;i<k;i++)
{
t[i+k]=c[i]-'0';
}
ans=0;
dfs(n-1);
printf("%d\n",ans);
return 0;
}