LibreOJ 10163 Amount of Degrees

题目链接:LibreOJ 10163 Amount of Degrees

题目大意:

题解:
主要思想是进制转换。
一个数\(x\)转换为\(b\)进制可以表示为\(x = a_0b^0 + a_1b^1 + a_2b^2 + ...\),题目要求的就是系数\(a_0,a_1,a_2,...\)中有\(k\)\(1\),其余是\(0\)的情况的个数。
于是我们将\(a_0,a_1,a_2,...\)排成一个序列\(a_0a_1a_2...\),题目就转变成求满足有\(k\)\(1\)\(01\)序列的个数。
\(dp[i][j]\)表示\(i\)\(01\)序列中\(1\)的个数为\(j\)的序列个数,则状态转移方程为:\(dp[i][j]=dp[i-1][j-1]+dp[i-1][j]\)
预处理出序列个数之后,将数\(x\)转换成\(a_0a_1a_2...\)系数序列,求字典序小于等于它的系数序列且\(1\)的个数不超过\(k\)\(01\)序列个数,即为\([0,x]\)区间内恰好等于\(k\)个互不相等的\(b\)的整数次幂之和的数的个数,记作\(count(x)\),则答案为\(count(y)-count(x-1)\)

#include <iostream>
using namespace std;

#define N 1010

int dp[35][35], x, y, k, b;

void init() {
    dp[0][0] = 1;
    for (int i = 1; i <= 31; ++i) {
        dp[i][0] = 1;
        for (int j = 1; j <= i; ++j) {
            dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
        }
    }
}

int count(int x) {
    int num[35], cnt = 0;
    while (x) {
        num[++cnt] = x % b;
        x /= b;
    }
    int ans = 0, tot = 0;
    for (int i = cnt; i >= 1; --i) {
        if (num[i] == 1) {
            ans += dp[i - 1][k - tot];
            if (++tot > k) {
                break;
            }
        } else if (num[i] > 1) {
            return ans += dp[i][k - tot];
        }
    }
    return tot == k ? ++ans : ans;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    init();
    cin >> x >> y >> k >> b;
    cout << count(y) - count(x - 1);
    return 0;
}
posted @ 2021-07-28 01:41  ZZHHOOUU  阅读(24)  评论(0编辑  收藏  举报