/**
* 数位dp:
* 第一道数位dp题,还是看《浅谈数位类统计问题》看到的题,
* 关于数位dp的理解,理解那棵完全二叉树就很容易理解了。
* 关键是对于非二进制的计数是如何根据二进制得出来的dp去计算的,、
* 拿5进制来说,比如 40132, bit[5] = {4,0,1,3,2}
* bit[len-1] = 4, 实现的时候逆序遍历: i = len-1 -> 0.
* 因为bit[len-1] > 1 也就是说,bit[len-1]位上的数减一之后其后的数都可
* 变成最大的数,在这里就是4,而bit[len-1] 仍然>= 1
* 所以转换成二进制思考的话就是 sum += dp[i+1][k-tot] //tot 是已经选了高位的几个1,此时还是0.
* 又因为dp[i+1][k-tot]已经涵盖了所有可能,不用再往前遍历,直接break就行
* 而如果bit[i]等于1,因为1减去之后为零,即使其后位都变成4.所以还需继续往前遍历。
* bit[i]等于0的时候就继续遍历。。
*/
#include <cstdio>
#include <iostream>
#include <cstring>
#define MAXN 33
using namespace std;
int x, y, k, b;
int dp[MAXN][MAXN];
void dpf()
{
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 1; i < 32; i ++)
{
dp[i][0] = 1;
for(int j = 1; j <= i; j ++)
dp[i][j] = dp[i-1][j] + dp[i-1][j-1];
}
}
int cal(int n, int k, int b)
{
int digit[MAXN], cnt = 0;
int tot = 0, ret = 0;
while(n)
{
digit[cnt++] = n % b;
n /= b;
}
for(int i = cnt - 1; i > 0; i --)
{
if(digit[i] > 1)
{
ret += dp[i+1][k-tot];
break;
}
else if(digit[i] == 1)
{
ret += dp[i][k-tot];
if(++tot > k) break;
}
}
if(tot == k) ret ++;
return ret;
}
int main()
{
dpf();
while(cin >> x >> y >> k >> b)
{
cout << cal(y, k, b) - cal(x-1, k, b) << endl;
}
return 0;
}
ural 1057 Amount of degrees 数位DP (入门)
最新推荐文章于 2019-06-11 14:56:00 发布