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;
}

看起来代码挺少的,但是其中的思维量不少的。

comments powered by Disqus