题意:
求最少需要多少个3的倍数按位或后可以得到数字a
思路:
如果a是3的倍数,那么我们直接取a即可
如果a的二进制只有一位或两位,我们根本取不出0以外的3的倍数,所以无解,题目保证有解所以可以基本不考虑太多
a的二进制至少有三位数的情况
1.每一个二进制位mod 3只能得到1或2
2.每个mod 3=2的数和mod 3=1的数相加一定是3的倍数
3mod3后余数相同的数相减以后一定也是3的倍数


若a mod3==1
如果a中的二进制位至少两个mod 3=1的,设他们为p和q,我么取{a-p,a-q}即可
因为q,p,q都是mod3==1的,所以a-p和a-q必定是3的倍数,同时a-p和a-q等于将原本p,q处的1变成了0,这样一来,a-p和a-q按位之后就还是a
举个例子 19


如果a中的二进制恰好有一个mod3=1的,那么设mod3=1的这一位为p,mod3=2的某个位为q,我们取{a-p,p+q}即可
a-p的道理同上,p+q因为一个mod3=1,一个mod3=2所以两者加起来一定是3的倍数,同时p+q与a-q按位或一定是a,因为a-p去掉p ,p+q给
补上了,多出的q是原本a中就有的所以没有什么影响


如果a中的二进制位没有mod3=1的,那么假设有三个mod3=2的位p,q,r,我们取{a-p-q,p+q+r}即可。
因为p和q都是mod3 =2,所以q+pmod3=1,就和a是一样的了,故a-p-q是3的倍数,又因为r也是mod3=2,所以q+p+r
原本是mod3=6,9可以除尽3,所以q+p+r也是3的倍数


若amod3=2
只需把上面的讨论中1与2互换即可,是完全对称的。

#include<bits/stdc++.h>
using namespace std;
vector<vector<int> > v;//v[1]保存mod3为1的二进制位,v[2]保存mod3为2的二进制位
int main(){
int n;
cin>>n;
while(n--){
v.resize(3);//必须写 ,且大于等于3
//resize只改变容器的元素,它是不会将容器的容量变小,
//只有当n大于容器的容量时,它才会改变容器大小(加大容量)。
//reserve操作允许我们通知容器它应该准备保存多少元素,reserve并不改变容器中元素的数量,
//它仅影响容器预先分配多大内存空间。
//注意:reserve只适用于vector和string
v.clear();
long long a;
cin>>a;
if(a%3 == 0){
printf("1 %lld\n",a);
continue;
}
int temp=1;
for(int i=0;i<61;i++){
if((a>>i)&1 == 1 ){
v[temp].push_back(i);
}
temp=3-temp;
}
int size1=v[1].size(),size2=v[2].size();
long long ans1,ans2;
if(size1>0&&size2>0)
{
if(a%3==1){
if(size1>=2){
ans1=a-(1ll<<v[1][0]);
ans2=a-(1ll<<v[1][1]);
printf("2 %lld %lld\n",ans1,ans2);
}
else{
ans1=a-(1ll<<v[1][0]);
ans2=(1ll<<v[1][0])+(1ll<<v[2][0]);
printf("2 %lld %lld\n",ans1,ans2);
}
}
if(a%3==2){
if(size1>=2){
ans1 = a-(1ll<<v[2][0]);
ans2 = (1ll<<v[1][0])+(1ll<<v[2][0]);
printf("2 %lld %lld\n",ans1,ans2);
}
else{
ans1=a-(1ll<<v[2][0]);
ans2=a-(1ll<<v[2][1]);
printf("2 %lld %lld\n",ans1,ans2);
}
}
continue;
}
if(size1 == 0){
if(a%3 == 1){
ans1 = a-(1ll<<v[2][0])-(1ll<<v[2][1]);
ans2 = (1ll<<v[2][0])+(1ll<<v[2][1])+(1ll<<v[2][2]);
printf("2 %lld %lld\n",ans1,ans2);
}
else{
ans1=a-(1ll<<v[2][0]);
ans2=a-(1ll<<v[2][1]);
printf("2 %lld %lld\n",ans1,ans2);
}
continue;
}
if(size2==0){
if(a%3==1){
ans1=a-(1ll<<v[1][0]);
ans2=a-(1ll<<v[1][1]);
printf("2 %lld %lld\n",ans1,ans2);
}
else{
ans1=a-(1ll<<v[1][0])-(1ll<<v[1][1]);
ans2=(1ll<<v[1][0])+(1ll<<v[1][1])+(1ll<<v[1][2]);
printf("2 %lld %lld\n",ans1,ans2);
}
continue;
}
}
return 0;
}