ural1057 Amount of Degrees ——数位DP
May 15, 2013
Ural
DP
题目链接: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
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
typedef long long int LL;
const int MAXN = 0x7fffffff;
const int MINN = -0x7fffffff;
const double eps = 1e-9;
const int dir[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,1},
{1,1},{1,-1},{-1,-1}};
int f[32][32];
int solve(int n, int k, int b) {
int a[32], sum, cnt, i, j;
sum = 0; cnt = 0; i = 0;
while (n) {
a[++i] = n%b; n /= b;
}
for (j = i; j >= 1 && cnt <= k; --j) {
if (a[j] > 1) {
sum += f[j][k-cnt]; break;
} else if (a[j] == 1) {
sum += f[j-1][k-cnt]; cnt++;
}
if (j == 1 && cnt == k) sum++;
}
return sum;
}
int main(void){
#ifndef ONLINE_JUDGE
freopen("ural1057.in", "r", stdin);
#endif
int x, y, k, b, i, j;
for (i = 0; i < 32; ++i) f[i][0] = 1;
for (i = 1; i < 32; ++i)
for (j = 1; j <= i; ++j)
f[i][j] = f[i-1][j] + f[i-1][j-1];
while (~scanf("%d%d%d%d", &x, &y, &k, &b)) {
printf("%d\n", solve(y, k, b) - solve(x - 1, k, b));
}
return 0;
}
看起来代码挺少的,但是其中的思维量不少的。