求给定区间[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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
URAL 1057 Amount of Degrees(数位统计)
原文:http://blog.csdn.net/u014664226/article/details/47622549