题意:
求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K 个互不相等的B的整
数次幂之和。
思路:对于二进制来说(图片摘自刘聪的浅谈数位类统计问题论文)
现在推广到b进制
因为对于b进制的每一位,我们只需要讨论这一位是否是一,所以我们可以把这个数转换为一个等价的二进制数,
方法是将这个数从左到右第一位不是零或一的位变为1,并把其右边的所有位置一,求出这个二进制数。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
#define pii (pair<int, int>)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
//const int maxn = 100 + 5;
//const int INF = 0x3f3f3f3f;
LL f[40][40];
int x, y, k, b;
void init() {
f[0][0] = 1;
for(int i = 1; i <= 31; i++) {
f[i][0] = 1;
for(int j = 1; j <= i; j++) {
f[i][j] = f[i-1][j] + f[i-1][j-1];
}
}
}
int cal(int x, int k) {
int tot = 0, ans = 0;
for(int i = 31; i > 0; i--) {
if((1<<i)&x) {
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 conv(int x) {
int ans = 0;
vector<int> v;
while(x) {
v.push_back(x%b);
x /= b;
}
int sz = v.size();
for(int i = sz-1; i >= 0; i--) {
if(v[i]==1 || !v[i]) {
ans += (v[i]==0 ? 0 : (1<<i));
}
else {
for(int j = 0; j <= i; j++) ans += (1<<j);
break;
}
}
return ans;
}
int main() {
//freopen("input.txt", "r", stdin);
init();
while(scanf("%d%d%d%d", &x, &y, &k, &b) == 4) {
//cout << conv(y) << endl << conv(x) << endl;
cout << cal(conv(y), k)-cal(conv(x-1), k) << endl;
}
return 0;
}