数的度量

https://www.acwing.com/problem/content/1083/

思路

这个题相当于把一个数字转化为\(b\)进制, 然后去看小于等于它的数中有多少个在\(b\)进制下, 有\(k\)\(1\)且其他位全部为0.

\(对于每一位x, 左边的分支为该位取0到x-1,首先该位可取0,然后有两种情况\)

  • 若x>1, 该位为0情况已算, 直接算该位为1的情况, 并且直接break.
  • 若x==1,同样该位为0情况已算, 那么该位只能取1并且接着看下一位.

\(右边的分支为取x\)

代码
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define pb push_back
#define PII pair<int, int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 35;
int k, b;
int C[N][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 f(int n) {
    if (!n) return 0;
    vector<int> num;
    while (n) num.pb(n % b), n /= b;
    n = num.size();
    int res = 0, last = 0;
    for (int i = n - 1; i >= 0; --i) {
        int x = num[i];
        if (x) {    //枚举选0 ~ x - 1的情况
            res += C[i][k - last]; //该位选0
            if (x > 1) {
                if(k - last - 1 >= 0) res += C[i][k - last - 1]; //该位选1, 后面选出k - last - 1个1
                break;
            }
            else {
                ++last;
                if (last > k) break;
            }
        }
        if (!i && k == last) ++res; //最右侧的分支
    }
    return res;
}
        
int main() {
    IO;
    init(); 
    int l, r;
    cin >> l >> r >> k >> b;
    cout << f(r) - f(l - 1) << '\n';
    return 0;
}


posted @ 2021-02-02 01:17  phr2000  阅读(87)  评论(0编辑  收藏  举报