异或运算法则:
相同为0,不同为1
异或性质:
1) 交换律 a^b=b^a
2) 结合律 a^b^c=a^(b^c)
3) 对于任意数 异或0得本身,异或本身得0,异或1得本身取反
一些相关例题:
位运算一类题基本操作:拆位
1)求连续区间 [ L , R ] 的异或和 题目链接:
解法: 显然 [ 0, 3 ],[ 4, 7 ],[ 8,11 ] …每四个异或和为0;利用该规律 可将求 [ L , R ] 转化为 求 [ 1, L - 1 ] , [ 1, R ] ,再利用异或的相关性质即可求解
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
ll l,r;
scanf("%lld%lld",&l,&r);
ll ans=0,ant=0;
l--;
if(l%4!=3){
for(ll j=l%4,i=l;j>=0;j--,i--){ans^=i;}
}
if(r%4!=3){
for(ll j=r%4,i=r;j>=0;j--,i--){ant^=i;}
}
printf("%lld\n",ant^ans);
return 0;
}
2)动态区间异或和
3) 从{1,2,3,4,…n}中找到一个最大的集合使得集合中任意两个数异或的结果比这两数的最小值还要小 题目链接:
4):给你一组数,让每个数都异或同一个数后,求异或后的最大值
题目链接:
解题报告: 进行拆位运算,一共就29位,从最高位开始,若当前位上全为1或者0,答案很明显;若当前位0和1都有,因为求最大值那么该位必然为1。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MOD=2147493647;
vector<ll>v1;
ll dfs(vector<ll>v,ll bit)
{
if(bit<0||v.size()==0){return 0;}
vector<ll>one,zero;
for(int i=0,j=v.size();i<j;i++){
if((v[i]>>bit)&1){one.push_back(v[i]);}
else{zero.push_back(v[i]);}
}
if(one.size()==0){return dfs(zero,bit-1);}
if(zero.size()==0){return dfs(one,bit-1);}
else{
return min(dfs(one,bit-1),dfs(zero,bit-1))+1ll<<bit;
}
}
int main()
{
int n;ll x;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&x);
v1.push_back(x);
}
printf("%lld\n",dfs(v1,29));
return 0;
}
5):题目链接:
题意:
求出最短的一组数满足异或和为u,算术和为v。
解题报告:
异或和相当于二进制下不进位的加法运算
考虑有解的情况:因为 a^b^b=a;不妨将 v=u+b+b,那么这组数最多三个,
当u,b的各二进制上不全为1说明他们可以合并可以更短。
注意特判一下 u==v u==0&&v==0
考虑无解的情况:u>v || u,v奇偶性不同
#define first f
#define second s
#define ll long long
#define mp make_pair
#define pb push_back
#define pf push_front
#define lb lower_bound
#define ub upper_bound
#include <bits/stdc++.h>
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MOD=1e9+7;
const int inf=1e9+7;
const int maxn=1e5+5;
const double eps=1e-6;
const double PI=acos(-1.0);
const double e=2.718281828459;
int main()
{
ll a,b;
scanf("%lld%lld",&a,&b);
if(a>b||(a+b)%2==1){printf("-1\n");return 0;}
if(a==0&&b==0){printf("0\n");return 0;}
if(a==b){printf("1\n%lld\n",a);return 0;}
ll tmp=(b-a)/2;
bool flag=false;
for(int i=0;i<63;i++){
if(((1ll<<i)&a)&&((1ll<<i)&tmp)){
flag=true;break;
}
}
if(flag){printf("3\n%lld %lld %lld\n",a,tmp,tmp);}
else{printf("2\n%lld %lld\n",a+tmp,tmp);}
return 0;
}
6):题目链接
解题报告:
拆位运算 也就最多64位;统计每位上 1 和 0 的个数,会发现任意三位异或后为 1 的情况只有 1^0^0 或者 1^1^1,再利用组合数学的方法分别计算一下即可。
#define first f
#define second s
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define sl(p) strlen(p)
#define SZ(p) p.size()
#include <bits/stdc++.h>
#define lb lower_bound
#define ub upper_bound
#define mem(a,b) memset(a,b,sizeof(a))
#define fast_cin ios_base::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL);
using namespace std;
const ll MOD=1e9+7;
const int maxn=2e5+5;
const int inf=0x3f3f3f3f;
const long double eps=1e-8;
ll q[65];
ll qpow(ll x,ll p)
{
ll ans=1;
while(p){
if(p&1) ans=ans*x%MOD;
x=x*x%MOD;
p>>=1;
}
return ans;
}
ll C(ll x,ll y)
{
if(x>y) return 0;
ll ans=1;
for(ll i=0;i<x;i++) ans=ans*(y-i)%MOD,ans=ans*qpow(i+1,MOD-2)%MOD;
return ans;
}
int main()
{
ll n,sum=0;
scanf("%lld",&n);
for(ll i=1,j;i<=n;i++){
scanf("%lld",&j);
int cnt=0;
while(j){
if(j&1) q[cnt]++;
cnt++,j>>=1;
}
}
for(int i=0;i<=62;i++){
sum+=(1ll<<i)%MOD*(C(3,q[i])+C(2,n-q[i])*q[i]%MOD)%MOD;
sum%=MOD;
}
printf("%lld\n",sum);
return 0;
}