牛客-随机数

题目传送门

-------------------上个星期的假日团队赛,这题别人的代码看了四五天才明白,来补上代码

sol1:排列组合,当考虑某一位本来是1的,现在改成了0,那么在这一位后面位的就可以随意排列组合了。

  • 排列组合
    #include "bits/stdc++.h"
    using namespace std;
    typedef long long LL;
    LL c[40][40];
    // 1100
    // 3210
    void init() {
        c[0][0] = 1;
        for (int i = 1; i <= 31; i++) {
            c[i][0] = 1;
            for (int j = 1; j <= i; j++)
            c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
        }
    }
    int slove(int n) {
        if (n == 0) return 0;
        int pos = 31, ans = 0;
        while ((n >> pos & 1) == 0) pos--;
        for (int i = pos - 1; i >= 1; i--) {
            for (int j = 0; j + 1<= (i + 1 >> 1); j++) ans += c[i][j];
        }
        int p = 1;
        for (int i = pos - 1; i >= 0; i--) {
            if (n >> i & 1) {
                for (int j = 0; j + p <= (pos + 1 >> 1); j++) ans += c[i][j];
                p++;
            }
        }
        if (p <= (pos + 1 >> 1)) ans++;
        return ans;
    }
    int main() {
        init();
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", slove(r) - slove(l - 1));
        return 0;
    }

     

sol2:数位dp,别人的代码里有一块看了好久看不懂,看懂之后觉得是冗余。。。。不过思路可学

  • 数位dp
    #include "bits/stdc++.h"
    using namespace std;
    int dp[32][64]; // 表示考虑到第i位,01个数差为j的方案数,因为j可能是负数统一加32 
    bool dig[32];
    int dfs(int i, int j, bool lim, bool head) { //枚举到哪一位,sum0-sum1,限制,是否有第一个1 
        if (i < 1) return j == 32;
        if (!lim && head && ~dp[i][j]) return dp[i][j];
        int up = lim ? dig[i] : 1, sum = 0;
        // 第i位取0的情况 
        if (!head) sum += dfs(i - 1, j, false, false);
        else sum += dfs(i - 1, j - 1, lim && dig[i] == 0, true);
        // 第i位取1的情况 
        if (up) sum += dfs(i - 1, j + 1, lim, true);
        if (!lim && head) dp[i][j] = sum; 
        return sum;
    }
    int slove(int k) {
        int pos = 0, sum = 0;
        while (k) {
            dig[++pos] = k & 1;
            k >>= 1;
        }
        for (int i = 0; i <= pos; i++) sum += dfs(pos, i + 32, true, false);
        return sum;
    }
    int main() {
        int l, r;
        scanf("%d%d", &l, &r);
        memset(dp, -1, sizeof(dp));
        printf("%d\n", slove(r) - slove(l - 1));
        return 0;
    }

     

posted @ 2019-07-14 21:38  Jathon-cnblogs  阅读(216)  评论(0编辑  收藏  举报