题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1057
题目大意:
意思就是给一个区间[x, y],求这个区间内有多少个恰好可以被k个b的不同次幂的数之和表示出来的数字的个数。
题目思路:
只需要求区间[0, m]内的恰好可以被k个b的不同次幂的数之和表示出来的数字的个数,定义这个函数是solve(m, k, b)。题目要求的就是:solve(y, k, b) - solve(x - 1, k, b)。
思路就是,转化成二进制考虑。把这个区间内的某个数字表示成b进制,要求的数字是转化成b进制之后,每一位的数字均为0或者1,这样的数字。
画一棵完全二叉树,根节点是0,左子节点是0,右子节点是1,高度从0开始记起,整棵树的根节点不用。则f[i][j]表示,高度为i的二叉树里面恰好含有j个1的数字的个数。那么就有:
f[i][j] = f[i-1][j-1] + f[i-1][j] 意思就是高度为i的树包含的数字里面,符合条件的数字的数目等于左右两棵子树的和。
当然数组f[i...n][0]都要初始化为1,因为长度为i...n的并且含有0个1的数字的个数总为1.
参考解题报告:http://hi.baidu.com/zyz913614263/item/a0215c20efefa01f42634a12
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cctype> 6 #include <stack> 7 #include <queue> 8 #include <deque> 9 #include <map> 10 #include <set> 11 #include <vector> 12 #include <cmath> 13 #include <algorithm> 14 #define lson l, m, rt<<1 15 #define rson m+1, r, rt<<1|1 16 using namespace std; 17 typedef long long int LL; 18 const int MAXN = 0x7fffffff; 19 const int MINN = -0x7fffffff; 20 const double eps = 1e-9; 21 const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1}, 22 {1,1},{1,-1},{-1,-1}}; 23 int f[32][32]; 24 int solve(int n, int k, int b) { 25 int a[32], sum, cnt, i, j; 26 sum = 0; cnt = 0; i = 0; 27 while (n) { 28 a[++i] = n%b; n /= b; 29 } 30 for (j = i; j >= 1 && cnt <= k; --j) { 31 if (a[j] > 1) { 32 sum += f[j][k-cnt]; break; 33 } else if (a[j] == 1) { 34 sum += f[j-1][k-cnt]; cnt++; 35 } 36 if (j == 1 && cnt == k) sum++; 37 } 38 return sum; 39 } 40 int main(void){ 41 #ifndef ONLINE_JUDGE 42 freopen("ural1057.in", "r", stdin); 43 #endif 44 int x, y, k, b, i, j; 45 for (i = 0; i < 32; ++i) f[i][0] = 1; 46 for (i = 1; i < 32; ++i) 47 for (j = 1; j <= i; ++j) 48 f[i][j] = f[i-1][j] + f[i-1][j-1]; 49 while (~scanf("%d%d%d%d", &x, &y, &k, &b)) { 50 printf("%d\n", solve(y, k, b) - solve(x - 1, k, b)); 51 } 52 53 return 0; 54 }
看起来代码挺少的,但是其中的思维量不少的。