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;
}