https://www.acwing.com/problem/content/1083/
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 35;
int l , r;
int K , B;
int f[N][N];
void init() // 预处理组合数**从 i 个 数中选择 j 个数
{
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] + f[i - 1][j - 1];
}
int dp(int n)
{
if(!n) return 0; // 特判一下边界是否是 0 可以不用判断
vector<int> nums;
while(n) nums.push_back(n % B) , n /= B; // 挖出当前的数的B进制下的每一位
int last = 0 , res = 0; // last 用来存用 1 的个数 res 用来存答案
for(int i = nums.size() - 1 ; i >= 0 ; i --) // 因为存的时候是从前向后存的 , 所以枚举的时候reverse一下
{
int x = nums[i]; // 取出当前这一位
// cout << x << endl;
if(x > 0) // 只有 > 0 才讨论
{
res += f[i][K - last];
// 当前这一位填 0 那么根据状态转移就是 f[i][K - last] 一共可以填 K - 已经填的 last个
if(x > 1)
{
// 当前这一位填 1 所以 last ++ 所以 f[i][K - last - 1];
if(K - last - 1 >= 0) res += f[i][K - last - 1]; //
break; // 不能取 > 1 的数
}else
{
last ++; // 取 x 本身
if(last > K) break; // > 就 break
}
}
if(!i && last == K) res ++; // 表示的是一直向右走
}
return res;
}
int main()
{
cin >> l >> r >>K >> B;
init();
cout << dp(r) - dp(l - 1) << endl;
return 0;
}