正题
题目链接:https://www.luogu.com.cn/problem/AT2382
题目大意
询问在[L,R][L,R][L,R]中选取一个或多个数,将它们按位或后能得到多少种不同的结果。
1≤L≤R<2601\leq L\leq R<2^{60}1≤L≤R<260
解题思路
我们先把高位的LLL和RRR都有的111都删除,因为它们之间的数都有这些111,显然没有用。
那么这样LLL和RRR的最高位就不同了,我们找到RRR的最高位2k2^k2k。
此时对于[L,2k)[L,2^k)[L,2k)中的数字都在LLL中,而且它们怎么或都不能超过2k2^k2k,所以这部分的答案就是2k−L2^k-L2k−L。
然后让这部分的数或上2k2^k2k,此时我们就有两个部分[2k,R][2^k,R][2k,R]和[L+2k,2k−1)[L+2^k,2^{k-1})[L+2k,2k−1)的数字。
先令L=L+2k−1L=L+2^{k-1}L=L+2k−1,然后我们分类讨论一下:
- R≥L−1R\geq L-1R≥L−1:此时[2k,2k−1)[2^k,2^{k-1})[2k,2k−1)都能直接有。
- R≥2k+2k−1R\geq 2^k+2^{k-1}R≥2k+2k−1:此时第k−1k-1k−1位为000的数都存在,然后我们让这一部分数或上2k+2k−12^k+2^{k-1}2k+2k−1,那也能得到所有第k−1k-1k−1位为111的数,所以同上。
- L<2k+2k−1L<2^k+2^{k-1}L<2k+2k−1:此时k−1k-1k−1位为111的数都可以得到,继续考虑k−1k-1k−1位为000,对k−2k-2k−2位同上分类讨论即可。
- R<2k+2k−1,L≥2k+2k−1R<2^k+2^{k-1},L\geq 2^{k}+2^{k-1}R<2k+2k−1,L≥2k+2k−1:此时对于k−1k-1k−1位为111的部分我们显然不可能异或出比LLL小的数字,而比其大的数字都在,所以这部分答案是2k−L2^{k}-L2k−L,对[2k,R][2^{k},R][2k,R]重新做一次上面的操作就好了。
时间复杂度:O(log2n)O(\log^2 n)O(log2n)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll A,B,ans;
signed main()
{scanf("%lld%lld",&A,&B);while(1){if(B<=1){ans+=B-A+1;printf("%lld\n",ans);return 0;}ll k=1ll;while(k*2ll<=B)k=k*2ll;if((A&k)&&(B&k)){A-=k,B-=k,k/=2ll;continue;}ans+=k-A;B-=k;k/=2ll;swap(A,B);while(k){if(A>B||A>=k){ans+=k*2ll;printf("%lld\n",ans);return 0;}if(B<k)ans+=k,k/=2ll;else{ans+=k*2ll-B;B=A;A=0;break;}}}printf("%lld\n",ans);return 0;
}