AtCoder Grand Contest 031_C - Differ by 1 Bit

题目链接、

题意:

给你一个n,a,b

让你构造一个序列,长度为2^n,以a开始以b结尾,中间任意两个相邻的元素二进制相差1位

例如 

2 1 3

输出

1 0 2 3

即,1开始,3结束,2^2个数01,00,10,11,相邻元素转化为二进制严格相差一位

题解:

首先,

一个n位的二进制数,与他严格相差一位的数一共有n个

例如:

与00相差一位的有10和01

与000相差一位的有100,010,001

考虑缩小问题规模,即n位与n-1位的关系

这里有一个很巧妙的想法就是n维超立方体

举例

一个2维超立方体(正方形)

0001
1011

 

3维(正方体)

 

先遍历n-1维超立方体然后再遍历n维超立方体(2个n-1组成1个n维)

就这样,可以写出一个dfs

代码源自、

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int n,a,b,sum;
void dfs(int x,int y,int ban){
    if(__builtin_popcount(ban^sum) == 1){printf("%d %d ",y,x^y);return;}
    for(int i=0;i<n;i++)if((~(ban>>i))&1 && (x>>i)&1)
        for(int j=0;j<n;j++)if((~(ban>>j))&1 && i!=j){
            dfs(1<<j,y,ban|1<<i);
            dfs(x^(1<<i)^(1<<j),y^(1<<i)^(1<<j),ban|1<<i);
            return;
        }
}
signed main(){
    scanf("%d%d%d",&n,&a,&b);
    sum = (1<<n)-1;
    if(__builtin_popcount(a^b)%2 == 0)return 0*puts("NO");
    puts("YES");
    dfs(a^b,a,0);
    return 0;
}

__builtin_popcount(x)表示求x在二进制上有几个1 

ban是一个标记变量,即,考虑的那些位在二进制上表现为1,那么在__builtin_popcount(ban^sum) == 1

就是说当ban和sum(111111,即n个1)相差只有1位,也就是说已经考虑完所有位数(除当前位)的时候可以判断输出了

 

 

想了好久这个东西怎么理解,最后我妥协了,模拟了下代码,大概懂了,但是,下次做到类似的题,大概还是不会、、

n = 3, a = 0 , b = 7

dfs层数xybancoutij
1111000000-01
2010000001-12
3100000011000,010--
3100110011110,010--
2100011001-21
3010011011011,001--
3010101011101,111-

-

即输出

YES
0 4 6 2 3 1 5 7

每层dfs中有两个dfs,容易看出(模拟出(瞎猜出)),这是拆分n维为两个n-1维立方体

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值