思路
- 对于一个数 n, 我们求他的 0 - n 的满足要求的方案数, 对于区间[l, r] = sum[r] - sum[l - 1]
- 我们先预处理组合数, 存下对应的值
- 我们这时取出n的每一位的值, 我们去判断一下这位的树, 如果这一位不是0, 我们直接加上这一位是0的情况, 就是这以为不选1, 前面选了last个1, 后面再选k - last个1, 就是f[i], k - last], 对于这一位大于1这种情况, 后面就可以随便选, 这一位选上1, 这样最后组成的数一定是小于n的, 对于这位是1的情况, 我们就只有选0或者选1, 0已经前面加上了, 所以就只需要处理1这种情况,但是由于1这种情况, 后面还需要讨论, 不能乱取, 所以这不符合组合数, 我们直接last++就行
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 35;
int f[N][N];
int x, y, k, b;
void init()
{
for(int i = 0; i <= 34; i++)
{
f[i][0] = 1;
for(int j = 1; j <= i; j++)
f[i][j] = f[i - 1][j - 1] + f[i - 1][j];
}
}
int dfs(int x)
{
if(!x) return 0;
vector<int> num;
while(x) num.push_back(x % b), x /= b;
int ans = 0;
int last = 0;
for(int i = num.size() - 1; i >= 0; i--)
{
int n = num[i];
if(n)
{
ans += f[i][k - last];
if(n > 1) // 这位就随便取
{
if(k - last - 1 >= 0)
ans += f[i][k - last - 1];
break;
}
else
{
last++;
if(last > k)
break;
}
}
if(!i && k == last)//特判一下最后的一种情况
ans++;
}
return ans;
}
int main()
{
cin >> x >> y >> k >> b;
init();
int ans = dfs(y) - dfs(x - 1);
cout << ans << endl;
return 0;
}