这是一道数位dp的题目,数位dp的题目一般会问,某个区间内,满足某种性质的数的个数。
对应的数位dp问题有相应的解题技巧:
1. 利用前缀和,比如求区间[x,y]中的个数,转化成求[0,y]的个数 -[0,x-1]的个数。
2. 利用树的结构来考虑(按位分类讨论)
该类题目的核心就是根据数位进行分类讨论。
#include<bits/stdc++.h>
using namespace std;
const int N = 35;
int K, B;
int f[N][N];
void init() {//求组合数
//模板:数位DP一般要预处理符合题意的组合数
for (int i = 0; i <= N; i++) {
for (int j = 0; j <= i; j++) {
if (!j)f[i][j] = 1;
else f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
}
}
}
int dp(int n) {//模板:n=0和最后一位要特判
if (!n) return 0;//如果n==0,那么就直接放回0
vector<int> v;
while (n) v.push_back(n % B), n /= B;
int res = 0;
int last = 0;//表示已经取了多少个1
for (int i = v.size() - 1; i >= 0; i--) {//从最高位对每一位数讨论
int x = v[i];
if (x) {
// res += f[i][K - last];//加上第i位取0的时候的组合数,也就是对于后面i位取k-last个1的数量
// if (x > 1)//如果x>1,就可以直接用组合数表示出来,不用进行讨论,也就是i位取1的时候,后面i位随便取k-last-1个1
// {
// if (K - last - 1 >= 0) res += f[i][K - last - 1];
// break;
// }
// else//如果x==1,那么i位取1的时候,还要进行讨论,后面i位不能随便取,也就不是组合数
// {
// last++;
// if (last > K) break;
// }
}
if (!i && last == K) res++;// 对于最后一位来特殊来考虑
}
return res;
}
int main()
{
init();
int l, r;
cin >> l >> r >> K >> B;
cout << dp(r) - dp(l - 1) << endl;
return 0;
}