zoukankan      html  css  js  c++  java
  • Less Coin Tosses(Gym

    L - Less Coin Tosses Gym - 102346L

    题目链接

    算法

    打表+找规律

    时间复杂度O(logN)

    1.题意说的是给定你n位的二进制串,除了成对的(就是指那些1的个数相同或0的个数相同的),那些不成对的数有几个。比如n为3时,可以有000,001,010,011,100,101,110,111这八种二进制数,其中001可以与010配对,011可以与110配对,剩余的无法再配对,所以最后输出4。

    2.看要求的数的范围2<=N<=10^18,非常大,所以说不可能暴力去做,一定存在某种规律。

    3.既然成对的就是指二进制串中1的个数相同,那么我们可以用组合数的知识来解决。即从n位数中挑m位为1,看这样的数有几个,若为偶数,则说明没有不成对的,否则说明有落单的,这时加1即可。总结得出下列公式:

    [displaystyle sum_{i=0}^n (C_{n}^{i}\%2) ]

    4.公式有了,问题来了,n这么大怎么算。对于这种题,很大可能性说明存在某种规律,如何找到规律,就需要打表实现。可以根据下列代码来打表。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    /*打表*/
    const int N = 1000;
    ll c[N][N];
    int n;
    ll res[N];
    void init()
    {
        for(int i = 0; i < N;i ++)
            for(int j = 0; j <= i; j++)
            {
                if(!j) c[i][j] = 1;
                else
                    c[i][j] = (c[i-1][j] + c[i-1][j-1]);
            }
    }
    int main()
    {
        init();
        for(int i = 2; i < N; i++)
        {
            for(int j = 0; j <= i; j++)
            {
                res[i] += (c[i][j] % 2);
            }
            cout << "res[" << i << "] = " << res[i] << endl;
        }
    }
    

    由于没有取余导致后面的数溢出变成负数了,不过没有关系,我们只需要看前面几个数就能找到规律。

    看上面这张图,仔细观察颜色相同的下划线标注的位置。好像成2的倍数的数他们的结果相同。好像还有点什么,那么我们就把每个数拆分成二进制数,找到他们在输出中的位置,仔细观察。

    将上图中二进制数对应的结果进行比对,再与二进制数本身的特征加以比较,发现最终的结果与n对应的二进制数中的1的个数有关。由此,得出了最终规律。

    5.总结一下,规律为n对应的二进制数中1的个数k,答案为2^k

    C++代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    /*打表
    const int N = 1000;
    ll c[N][N];
    int n;
    ll res[N];
    void init()
    {
        for(int i = 0; i < N;i ++)
            for(int j = 0; j <= i; j++)
            {
                if(!j) c[i][j] = 1;
                else
                    c[i][j] = (c[i-1][j] + c[i-1][j-1]);
            }
    }
    int main()
    {
        init();
        for(int i = 2; i < N; i++)
        {
            for(int j = 0; j <= i; j++)
            {
                res[i] += (c[i][j] % 2);
            }
            cout << "res[" << i << "] = " << res[i] << endl;
        }
    }
    */
    ll n;
    int main()
    {
        cin >> n;
        ll res = 1;
        while(n)
        {
            if(n & 1) res <<= 1;
            n >>= 1;
        }
        cout << res ;
        return 0;
    }
    

    代码中求组合数的模板来源于yxc大佬的数学知识模板

  • 相关阅读:
    23种设计模式中的模板模式
    23种设计模式中的外观模式
    div,li,span自适应宽度换行问题
    监听自定义ItemRender的事件
    flex acionscript png图片去除多余空白,生成合适大小图片
    项目中用到RouteTable,发布到IIS7中无法访问
    记录Castle ActiveRecord访问Sqlite的配置
    如何卸载软件
    linux 下route命令
    linux 下 ifcfg-eth0 配置 以及ifconfig、ifup、ifdown区别
  • 原文地址:https://www.cnblogs.com/KeepZ/p/13743591.html
Copyright © 2011-2022 走看看