牛客网暑期ACM多校训练营7: C. Bit Compression(DFS+预处理)

题目描述

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

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/81542743