题目描述
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-1s2i with 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.
输入
2 1001
输出
4
直接爆搜复杂度是O(18*3^18)的,不剪枝会超时
仔细分析可以发现每次递归都会使当前数组长度缩小一半,倒数第5次搜完后长度就变为16了
所以可以预处理2^16种情况下的答案,这样就可以使搜索的深度-3,复杂度变为O(16*2^16+18*3^14),可以过
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stdlib.h>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
char str[300005];
LL sum;
bool p[300005], P[19][300005];
int ans[66666], jud, er[21] = {1};
void Sech(int id, int len, int all)
{
int i, j, now, cnt;
if(id+3==len && len>=5)
{
sum += ans[jud];
return;
}
if(id==len+1)
{
sum += p[1];
return;
}
for(i=1;i<=3;i++)
{
cnt = 0;
for(j=1;j<=all;j++)
P[id][j] = p[j], cnt += p[j];
if(cnt==0)
return;
cnt = jud = 0;
for(j=1;j<=all;j+=2)
{
if(i==1) p[++cnt] = p[j]|p[j+1];
if(i==2) p[++cnt] = p[j]&p[j+1];
if(i==3) p[++cnt] = p[j]^p[j+1];
jud = jud*2+p[cnt];
}
Sech(id+1, len, cnt);
for(j=1;j<=all/2;j++)
p[j] = P[id][j];
}
}
int main(void)
{
int n, len, i, j, now;
for(i=1;i<=18;i++)
er[i] = er[i-1]*2;
scanf("%d", &n);
len = min(er[n], 16);
for(i=0;i<(1<<len);i++)
{
for(j=0;j<=len-1;j++)
{
p[j+1] = 0;
if(i&(1<<j))
p[j+1] = 1;
}
now = 0;
for(j=1;j<=len;j++)
now = now*2+p[j];
sum = 0;
Sech(1, min(n, 4), len);
ans[now] = sum;
}
if(n<=4)
{
now = 0;
scanf("%s", str+1);
for(i=1;str[i]!=0;i++)
now = now*2+str[i]-'0';
printf("%d\n", ans[now]);
}
else
{
sum = 0;
scanf("%s", str+1);
for(i=1;str[i]!=0;i++)
p[i] = (str[i]-'0')==1;
Sech(1, n, i-1);
printf("%lld\n", sum);
}
}