题目
t(t<=1e4)组样例,每次给定a,b,d(1<=a,b,d<2的30次方)
求是否存在一个x(0<=x<2的60次方),满足(a|x)是d的倍数,且(b|x)是d的倍数,
其中|为二进制下的or,存在的话输出任意一个x即可,如果不存在,输出-1
思路来源
官方题解&rainboy&inszva代码
题解
代码1(官方题解)
先判断不合法的情形,
如果d为偶数,此时a和b如果有一个为奇数,则肯定无解,a%d必有余数
否则令d/2,a/2,b/2,继续判断,中途无解提前退出,...,直到d为奇数,
d为奇数后,一定有解,即任意数都有解,此时不妨令x=a|b,
为x构造出解之后,(a|x)=x,(b|x)=x,x也是原问题的解,
等价于解同余方程,
其中c为前面除以2的次数,两边同乘即可还原成原来的式子
先移项,然后由于d为奇数,,
可求2的逆元inv(2),实际上就是(d+1)/2,两侧同乘即可得到t,
,代入即可求得x
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,a,b,c,d,v;
int main(){
cin>>t;
while(t--){
cin>>a>>b>>d;
c=0;
while(a%2==0 && b%2==0 && d%2==0){
a/=2,b/=2,d/=2;
c++;
}
if(d%2==0){
cout<<-1<<endl;
continue;
}
int inv=(d+1)/2;
v=1;
for(int i=0;i<30-c;++i){
v=1ll*v*inv%d;
}
int r=((d-(a|b))%d+d)%d;
ll x=1ll*v*r%d;
a<<=c;b<<=c;
cout<<((x<<30)|(a|b))<<endl;
}
return 0;
}
代码2(inszva代码)
先判完不合法的情形
注意到d是一个奇数,所以可以起到对某一位赋1的作用,
从低位到高位考虑最后30位,低位已经为1了,高位的相加就不会影响低位
每次加上的都是d的倍数,最终答案一定是d的倍数,
这样还能保证二进制最后30位全是1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll a,b,d,v;
int main(){
cin>>t;
while(t--){
cin>>a>>b>>d;
int c=0;
while(a%2==0 && b%2==0 && d%2==0){
a/=2,b/=2,d/=2;
c++;
}
if(d%2==0){
cout<<-1<<endl;
continue;
}
ll x=0;
for(int i=0;i<30;++i){
int bit=x>>i&1;
if(!bit){
x+=d<<i;//d奇数 必能使第i位为1
}
}
cout<<(x<<c)<<endl;
}
return 0;
}