2019牛客暑期多校训练营(第四场) D triples I

传送门

题目简介:

就是给你一个数,要你求出能够 或运算 出原数并且你的数能被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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值