题目简介:
就是给你一个数,要你求出能够 或运算 出原数并且你的数能被3整除的最小个数。
链接:https://ac.nowcoder.com/acm/contest/884/D
来源:牛客网
输入
2
3
7
输出
1 3
2 3 6
说明
3=3, (3|6)=7
这题就是一个小学的思路,我们都知道十进制中,任意一个数只要每一位相加的和能被3整除,那么这个数就能被3整除。
这是为什么?
因为十进制中每一个位都会10^k次方,那么仅仅是每一位%3的值都是余1,那么我们只要凑3个余1的,那么3就能被这个数整除。
这题思路一样,换成2进制,那么二进制每一位都是2^k次方,简单的写一下,2^0 % 3是 1,2^1 %3是2, 2^2%3是1,2^4 %3是2,那么我们就找出规律,在二进制中,偶数次位有1,代表能有个余数1;奇数次位有1,代表有个余数2;接下来就是分情况讨论了。
首先我们要确定一点,如果给的数能被3整除,那么他本身就是答案;如果不能被3整除,那么我们就加减余数位即可,所以最多只有2个数就可以 或 出原数。
如果a的二进制只有一位或两位,我们根本取不出0以外的三的倍数,所以无解。题目保证有解所以可以基本不考虑太多。
如果a的余数是1(2),
并且在偶数(奇数)位上有1,
x就是原数减去对应2进制偶数(奇数)位1,
y就想办法凑成余数是3,这里y可以有两种凑法,
一种是直接取原数位置上一个奇数位(余数2)和原数上一个偶数为(1),
另一种是用原数减去另一个减去对应2进制偶数(奇数)位1,
这样就可以凑成3的倍数并且和x或运算得到原数;
如果偶数(奇数)位上没有1,
那么我们就没办法像上面一样直接在原数上减去余数,假设我们需要凑1(偶数位),但是原数没有1的,那么我就凑两个2(两个奇数位),这样余数就是4,%3就是1,这样们就能凑出一个1,凑2只需2个1,x就可以这么写。
接下来我们再凑y,假设我们没有1,那么我们就拿3个2出来,得6,也可被3整除,没有2就拿3个1。
到此,思路结束。(小时候的知识漏洞,欠下的账迟早要还)。
ac代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a;
void solve(){
scanf("%lld",&a);
vector<ll> bb[2];
for(int i=0;i<=60;i++)
if((a>>i)&1) bb[i&1].push_back(1LL<<i); //记录每一个1的位置和保存他的奇偶
if(a%3==0)
printf("1 %lld\n",a); //本身
else if(bb[1].size()+bb[0].size()<=2) return;//凑不出
else{
ll x,y;
int s = (a%3==2); //余数是2还是1
if(bb[s].size()){//如果原数里有我们需要的,可以直接减去的
x = a-bb[s][0];
if(bb[!s].size()) y = (bb[s][0]) + (bb[!s][0]); //凑3的两种方式
else y = a - bb[s][1];
}else{ //原数里没有余数
x = a-(bb[!s][0]+bb[!s][1]);
y = bb[!s][0]+bb[!s][1]+bb[!s][2];
}
printf("2 %lld %lld\n",x,y);
}
}
int main(){
int T; cin>>T;
while(T--){
solve();
}
return 0;
}