Bit Compression 两种解决方案 O(∩_∩)O哈哈~

题目链接

方法一(暴力):这题很容易看出来是个典型的dfs题,只要注意剪枝(把结果一定为0的情况进行剪枝)就能过,下面是代码:

#include<cstdio>
using namespace std;
bool a[1 << 18];
int dfs(int n, bool* s) {
	if (n == 1) return 1;
	n >>= 1; bool b[n]; int ans = 0, h1 = 0, h2 = 0, h3 = 0;
	for(int i=0;i<n;++i)h1+=b[i]=(s[i<<1]&s[i<<1|1]); if(h1)ans+=dfs(n,b);
	for(int i=0;i<n;++i)h2+=b[i]=(s[i<<1]|s[i<<1|1]); if(h2)ans+=dfs(n,b);
	for(int i=0;i<n;++i)h3+=b[i]=(s[i<<1]^s[i<<1|1]); if(h3)ans+=dfs(n,b);
	return ans;
}
int main() {
	int n; scanf("%d%*c", &n);
	for(int i=0;i<(1<<n);++i) a[i]=getchar()-'0';
	printf("%d\n", dfs(1 << n, a));
	return 0;
}

方法二(非暴力): 对dfs进行记忆优化,用数位dp求得二进制颠倒排序,高精度压位防止数据溢出等。(速度要比暴力法快很多)代码如下:

#include<cstdio>

using namespace std;

const int  N  = 1 << 18;

int a[N], pos[N], b[N];// a存储输入串,pos存储序列,b存储记忆化 
unsigned c[N], d[N];// c存储高精度压位,d存储过程临时数据 

void Bitsort(int n) { // 数位dp 
	for(int i = 0; i <= (1 << n); ++i) {
		pos[i] = pos[i>>1]>>1|(i&1)<<(n-1);
	} 
}

int pre(int n, int last) { // 记忆优化 
	if (n == 1) return last&1;
	n >>= 1;
	int x = last, y = last >> n;
	return pre(n,x&y)+pre(n,x|y)+pre(n,x^y);
}

int dfs(int n, unsigned* last, unsigned* next) { // dfs
	if (n == 1 ) return last[0] & 1;
	if (n == 16) return b[last[0] & 0xffff];
	int ans = 0;
	if (n > 32){
		int temp = n / 64;
		for(int i = 0; i < temp; ++i) next[i] = last[i] & last[i+temp];
		ans += dfs(n / 2, next, next + temp);
		for(int i = 0; i < temp; ++i) next[i] = last[i] | last[i+temp];
		ans += dfs(n / 2, next, next + temp);
		for(int i = 0; i < temp; ++i) next[i] = last[i] ^ last[i+temp];
		ans += dfs(n / 2, next, next + temp); 
	}
	else {
		int x = last[0];
		int y = last[0] >> n / 2;
		next[0] = x & y;
		ans += dfs(n / 2, next, next + 1);
		next[0] = x | y;
		ans += dfs(n / 2, next, next + 1);
		next[0] = x ^ y;
		ans += dfs(n / 2, next, next + 1);
	}
	return ans;
} 

int main() {
	int n;
	scanf("%d%*c", &n);
	/******************************** 
	二进制颠倒排序 
	以二进制颠倒序列输入 
 	高精度压位(以二进制32位 -> 十进制) 
 	在进行深搜前对n=4,进行记忆化 
	***********************************/
	Bitsort(n);
	for(int i=0;i<1<<n;++i) a[pos[i]]=getchar()-'0';
	for(int i=0;i<1<<n;++i) c[i/32]|=(unsigned)a[i]<<(i%32);
	for(int i=0;i<1<<16;++i) b[i]=pre(16,i);
	printf("%d\n", dfs(1 << n, c, d)); 
	return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值