A. XOR Equation(dfs大法好哇)

注 意 到 x 和 s 最 大 才 40 位 二 进 制 注意到x和s最大才40位二进制 xs40

想 到 了 什 么 ? 爆 搜 ! ! \color{Red}想到了什么?爆搜!! ?!!

从 第 40 位 二 进 制 开 始 爆 搜 从第40位二进制开始爆搜 40

当 x 的 这 一 位 是 1 , 说 明 两 个 数 字 二 进 制 在 这 位 有 且 仅 有 一 个 是 1 \color{orange}当x的这一位是1,说明两个数字二进制在这位有且仅有一个是1 x1,1

所 以 这 里 方 案 数 乘 上 2 , 和 加 上 这 一 位 二 进 制 继 续 往 下 搜 所以这里方案数乘上2,和加上这一位二进制继续往下搜 2,


当 x 这 一 位 是 0 , 说 明 两 个 数 字 二 进 制 在 这 位 要 么 都 是 0 , 要 么 都 是 1 \color{Red}当x这一位是0,说明两个数字二进制在这位要么都是0,要么都是1 x0,0,1

是 0 就 什 么 都 不 加 , 继 续 往 下 搜 是0就什么都不加,继续往下搜 0,

是 1 就 加 上 这 一 位 二 进 制 的 两 倍 ( 两 个 数 ) , 继 续 往 下 搜 是1就加上这一位二进制的两倍(两个数),继续往下搜 1(),

剪枝

很好想,当两个数后面的二进制全都选1的和还是小于s,结束

当两个数和已经大于s,结束

细节

我们这样搜可能搜出某个数为0的情况

但题目要求是正数

所以搜的时候记录一下,有没有选过1,没得话就减掉

#include 
using namespace std;
typedef long long ll;
ll fac[100009],s,x,pre[10009],ans;
void dfs(ll num,ll u,ll k,ll ok)//num是哪一位二进制,u表示当前总和 
{
	if( num==-1 )
	{
		if( u==s )
		{
			ans+=fac[k];
			if( !ok )	ans-=2;
		}
		return;
	}
	if( x&fac[num] )
		dfs(num-1,u+fac[num],k+1,ok);//一个选0,一个选1 
	else
	{
		int flag=0;
		if( u+2*fac[num]<=s )	flag=1,dfs(num-1,u+2*fac[num],k,1);//选1
		if( pre[num-1]*2+u>=s )	flag=1,dfs(num-1,u,k,ok);
	}
}
int main()
{
	fac[0]=1,pre[0]=1;
	for(int i=1;i<=40;i++)	fac[i]=2*fac[i-1],pre[i]=pre[i-1]+fac[i];
	cin >> s >> x;
	dfs(40,0,0,0);
	cout << ans;
} 

你可能感兴趣的:(CF刷题计划)