Codeforces Round #456 B题

Posted 565261641-fzh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #456 B题相关的知识,希望对你有一定的参考价值。

技术分享图片

一、题意

  给你一个n和一个k,让你从[1, n]区间内选k个数,这k个数异或和最大。

二、思路

  我一开始看到这种题,不自觉地就想到,莫非又要搞很复杂的线段树、主席树?貌似还有些难搞啊。然而事实是:Codeforces最不喜欢出的题目就模板题,相反,他的题更倾向于想法,看看你能不能想到,能不能考虑全。我个人觉得,这样的题做起来还更有意思。

  事实是,这题的思路:选k个数,使异或和最大,那么,两种情况:

  (1)k = 1,那毫无疑问选最大的数,输出n;

  (2)k > 1,那就输出2i - 1。其中,i是n的二进制表示的长度。PS:前导0肯定不算的啦,从最高位1开始算起。

  PS:异或很重要的性质,这个是必须掌握的哦。二进制中,任何数(0或1),和0异或,都是它本身。

三、吐槽&总结时间

  我想到差不多上面的思路后,一开始想的是,考虑最大的那个数的二进制表示s,如果s中0的个数 <= k,那么,肯定能找到k个比n小的数,他们就是2i。这样,把他们全部和s逻辑,最后输出s的十进制就OK了。然后,被hack了T_T

  想了好长一会儿,终于发现,上面的方法有问题,如果s中0的个数 > k,也可以把s中的0变成1啊,可以选2i+2j 这种的啊。既然这样,那么,我就产生了一个很想想就觉得很傻逼的想法:既然输入数据k >= 1,那么,答案永远都是2i - 1(其中,i是n的二进制表示的长度)。我当时脑中的想法是:去[1, n]里面选k个数,和n异或的最大值。尽管我看了很多遍题目。也看了很多遍a1⊕a2⊕……⊕ak,都没发现自己的想法有错,所以,第二次提交又hacked,而且,我提交后,很肯定地认为自己没错了,把题目锁了,想去hack别人一发,消消气,结果,我那题就这样错了。直到写这篇题解前,我去补题,把昨晚的代码交上去被样例20卡掉了,我才顿悟:真的太糊涂了。

  很多次比赛都是这样,并不是自己想不到那个点子,而是总是被某个非常不起眼卡到绝望、卡到失败。

  这个我觉得这毛病和心态有关,要好好调整。一定要,必须要。

四、源代码

  

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    LL a, b;
    while(~scanf("%lld%lld", &a, &b)) {
        if(b == 1){
            printf("%lld\\n", a);
            continue;
        }
        int i = 0;
        for(i = 0; a > 0; ++i) {
            a >>= 1;
        }
       printf("%lld\\n", (1LL << i) - 1);
    }
    return 0;
}

以上是关于Codeforces Round #456 B题的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #774 (Div. 2)题解

Codeforces Round #774 (Div. 2)题解

Codeforces Round #456 (Div. 2)

Codeforces Round #456 (Div. 2) CPerun, Ult!

Codeforces 456 A. Laptops

Codeforces Round #340 (Div. 2) B