【GDOI2018模拟7.6】吃干饭

Description

求区间[l,r]中的数任意互相异或之后有多少种可能的结果
l<=r<=1e18,数据组数<=100

Solution

这种题一眼线性基啦~
虽然我并不太熟练,还自己推了一遍插入
这样直接暴力做有50分
然后打了个表发现了一个规律:
首先l一定会在线性基中,
然后我们知道了线性基中的最后一个数,想要快速找出线性基中的下一个数
假设当前的数的二进制表示是 10100,那么接下来的会是
10100
10101
10110
11000
11100
也就是每次找当前最后一个数中,从最低位起第一个当前位为0且线性基为空的位置
然后这一位是1,后面就都是0,并插入到这一位的线性基中
感性理解一下好像没什么毛病
那就直接模拟这个过程就好了,复杂度O(T log^2 L)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define fd(i,a,b) for(ll i=a;i>=b;i--)
using namespace std;
typedef long long ll;
ll l,r,ans,a[61],mi[61];
int main() {
    freopen("A.in","r",stdin);
    freopen("A.out","w",stdout);
    int ty;
    mi[0]=1;fo(i,1,60) mi[i]=mi[i-1]*2;
    for(scanf("%d",&ty);ty;ty--) {
        scanf("%lld%lld",&l,&r);
        if (!l&&!r) {
            printf("1\n");
            continue;
        }
        fo(i,0,60) a[i]=0;
        ll x=l;ans=2;if (!x) x=1;
        fd(i,60,0) if (x&mi[i]) {a[i]=x;break;}
        while (x<r) {
            int now=61;
            fo(i,0,60)
                if (!a[i]&&!(x&mi[i])) {
                    now=i;
                    break;
                }
            if (now>60) break;
            fo(i,0,now-1) if (x&mi[i]) x-=mi[i];
            x+=mi[now];a[now]=x;
            if (x<=r) ans=ans*2;
        }
        printf("%lld\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值