异或三角-----蓝桥杯

 声明:

思路和板子都来源于异或三角icon-default.png?t=N4P3https://blog.youkuaiyun.com/a12377978/article/details/124893215#comments_26867660

上面那篇帖子写的已经比较详细了,但是可能由于答主对二进制的思维实在不敏锐,所以有些点想了很久才相通,希望对以上帖子进行补充,在帮助大家的同时,加强一下我自己的理解。

思路:

性质1.由条件二知道,a,b,c互不相等,且

111011......
101001......
011110......
我们假设把a、b、c转为二进制表示后分别填入第1、2、3行。根据 三个数每一位按位异或都要为0,那么就是每一列只能有两种情况,即 两个1或者三个0




性质二:状态转移
假如a和b确定了,那么c=a^b。所以我们只需要枚举a、b的每一位即可。
我们假设a是三角形的最长边,bc是短边,在枚举完结果后答案乘以3就是本题答案。

从高到低位枚举,必须满足以下条件:
(0,1)在(1,0)之后出现,为了a>b
(0,1)在(1,1)之后出现,为了a>c

这两种情况应该比较好想,目的都是为了保证a是最大的,不理解的可以画图。或者去看一下这篇博客
(16条消息) 【蓝桥刷题】备战国赛——异或三角_DAY Ⅰ的博客-优快云博客

在枚举完ab的每一位后,必然存在至少一次的状态为(0,1)------这个条件感觉他们都没说清楚,目的是为了保证满足题意,即abc组成三角形

首先我们知道,异或运算也叫做二进制不进位加法|
这里我们要满足a<b+c三角形的规则
a<b+c    ---->    b^c<b+c
因为b^c相当于二进制的不进位加法
我们把左右两边都先转化为二进制后做加法
左边如果出现11那么本位不进位之间变成0,右边进1变为0.
如果有b^c<b+c,那么一定至少存在一次bc的状态为11
我们就可以得出结论 ab必然存在至少一次的状态为(0,1)



性质三:状态压缩


我们用到的状态为01,10,11,这是第一次状态压缩。
再做状态压缩,用三位二进制分别表示三种状态是否出现过    111(第一个1表示状态11已经出现过,第二个1表示状态10出现过,第三个1表示状态01出现过)

代码

 
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;


int nums[32];
LL f[32][2][8];

LL dfs(int u,int limit,int state){
    if(!u)return state==7;//如果走完
    LL &t=f[u][limit][state];
    if(~t)return t;//如果f[u][limit][state]计算过
    LL res=0;
    
    int up=limit?nums[u]:1;
    for(int i=0;i<=up;i++){
        if(!i){//a的当前位取0
            // 0 0
            res+=dfs(u-1,limit&i==up,state);
            if(state>=6)//在这个地方做限制
            //0 1  我们必须保证1 1和1 0已经出现过即110=6
            res+=dfs(u-1,limit&i==up,state|1);
        }
        else{
            // 1 0  ->010
            res+=dfs(u-1,limit&i==up,state|2);
            // 1 1  ->100
            res+=dfs(u-1,limit&i==up,state|4);
        }
    }
    return t=res;
}

LL dp(int x){
    int cnt=0;
    memset(f,-1,sizeof f);
    while(x)nums[++cnt]=x&1,x>>=1;
    
    return dfs(cnt,1,0)*3;
}

int main(void){
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        
        printf("%lld\n",dp(n));
    }
    
    return 0;
}

结语:
大家蓝桥杯国赛一起加油!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值