• 注册
当前位置:1313e > 默认分类 >正文

Android实训做一个QQ的代码,腾讯2018安卓实习模拟笔试题——小Q硬币组合

为什么每次看到这种题的超简短解题代码都会有一种“哇!”的感觉

题意

小Q非常富有,拥有非常多的硬币,小Q的拥有的硬币是有规律的,对于所有的非负整数K,小Q恰好各有两个数值为2^k的硬币,所以小Q拥有的硬币是1,1,2,2,4,4,8,8……,小Q卖东西需要支付n元钱,请问小Q想知道有多少种组合方案。(如果两种方案某个面值的硬币选取的个数不一样就考虑为不一样的方案)

输入

输入:一个n (1<=n<=10^18),代表要付的钱

6

输出

输出:表示小Q可以拼凑的方案数目

3

思路

除了暴力法,毫无思路,真的不会,大家还是看看以下大神级别的思路吧。

这道题我们应该理解为是要进行一种加法,和已经给定为n。然后我们现在有很多种2的k次方的值,要找出所有能加出n的方案。考虑到我们要加的数都是些2的k次方数,这其实跟二进制的位数相加很像,每个硬币都是二进制位数上的一位,而且我们恰好不同种硬币各有两个,即有两个2^0、两个2^1、两个2^2……把这些硬币等分成两份,正好就是两个二进制数,所以可以相当于两个二进制数数相加要得到n(大家自己看下图悟一下)

d20e780b8c6248dfbe7582b9940810e1.png

我们的硬币等分成两行,每一个硬币都是每行上的一个0,因此这就是两个长度为log2(n)的二进制数的相加,和为长度为log2(n)+1的数且首位为1其余位为0。

现在,再将上面图中的两行用十进制的眼光来看,就是十进制要加出个n总共有多少种组合方式,这个就是小学题了,比如n为8,有0+8,1+7,2+6,3+5,4+4。

走到这你就可以理解这份代码了,我们只需要注意两点:

①、假如n为8,是允许如1000和000相加的情况的,也就是硬币8和0(不拿)。

②、111+001(硬币421和硬币1)和101+011(硬币41和硬币21),只是前者选了第一行中面值为1的硬币,后者选了第二行中面值为1的硬币,本质上都得算同一种组合方法,也就是4211和4211都是同一种分法。因此我们可以考虑使用二进制异或来对这种类型进行去重(这样上0下1和上1下0结果都一样了)。

结果都一样后方案还是双份的呀,怎么变成一份呢。可以用set(注意这个容器)来保存抑或结果,这样就去重变成一份了。

代码

# include

# include

using namespace std;

int main(void) {

int n;

cin >> n;

set countset;

for (int i = 0; i <= n/2; i++) {

int result = i^(n-i); // 对两行进行抑或

countset.insert(result);

}

cout << countset.size() << endl;

return 0;

}

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 162202241@qq.com 举报,一经查实,本站将立刻删除。

最新评论

欢迎您发表评论:

请登录之后再进行评论

登录