NKOJ5059 幂和的数量 数位DP

题面:写一个程序来计算区间[X,Y]内满足如下条件的整数个数:它恰好等于K个互不相等的B的整数幂之和。

解法:设f[i][j]表示长度为i的二进制数中,数字1出现了j次的数的个数。转化为求Cnt[n]:在[1…n]区间的B进制表示中,只由数字0和1构成,且数字1出现次数为k的数字个数。

前面讨论的是二进制(B==2)的情况,怎么处理非二进制的情况呢?

找到n的左起第一位非0、1 的数位,将它变为1,并将右面所有数位设为1。
将得到的B进制表示视为二进制,然后按照前面的讨论进行询问即可。

#include <bits/stdc++.h>

using namespace std;

int f[105][105];
int x, y, k, b;

int getcnt(int x, int k)
{
    int tot = 0, ans = 0;
    for (int i = 31; i; i--)
    {
        if (x & (1 << i))
        {
            tot++;
            if (tot > k) break;
            x ^= (1 << i);
        }
        if ((1 << (i - 1)) <= x) ans += f[i - 1][k - tot];
    }
    if (tot + x == k) ans++;
    return ans;
}

int change(int x)
{
    int p = 1, tot = 0, ans = 0;
    while (x >= p * b) p *= b, tot++;
    while (p && x / p <= 1) ans += x / p * (1 << tot--), x %= p, p /= b;
    ans += (1 << (tot + 1)) - 1;
    return ans;
}

int main()
{
    scanf("%d%d%d%d", &x, &y, &k, &b);
    f[0][0] = 1;
    for (int i = 1; i <= 31; i++)
    {
        f[i][0] = f[i - 1][0];
        for (int j = 1; j <= i; j++)
        {
            f[i][j] = f[i - 1][j] + f[i - 1][j - 1];
        }
    }
    printf("%d", getcnt(change(y), k) - getcnt(change(x - 1), k));
}

 

posted @ 2021-01-06 19:49  Chasing-Dreams  阅读(115)  评论(0)    收藏  举报