数位DP度的数量

81 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第20天,点击查看活动详情

求给定区间 [X,Y][X,Y] 中满足下列条件的整数个数:这个数恰好等于 KK 个互不相等的 BB 的整数次幂之和。

例如,设 X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意:17=24+2018=24+2120=24+22例如,设 X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意: \\ 17=24+20 \\ 18=24+21 \\ 20=24+22 \\

限制:

1XY2311,1K20,2B101≤X≤Y≤231−1, \\ 1≤K≤20, \\ 2≤B≤10 \\

思路

数位就是把一个数字按照个、十、百、千等等一位一位地拆开来看看待

比如我们常用十进制,就是进位权是10的数

当然,我们可以有其他进制了,如二进制,八进制,三进制等等

数位DP:

用来解决一类问题,一般满足求某个区间满足条件的数的数量,并且这个问题可以转换之后,我们的数位dp去解决用来解决一类问题,一般满足求某个区间满足条件的数的数量,并且这个问题可以转换之后,我们的数位dp去解决

管用伎俩,区间高达23112^{31}-1

题目,要求一个区间内的满足条件的数,那么,区间具有累加性的话。

我们就可以将区间RLR 到 L 转化为 fun(R)fun(L1)fun(R) - fun(L-1)的区间

说回题目

题目明确要求,求B进制下的数位满足k的数字

对于B进制来说,满足整数次幂的系数为1,所以,我们这个题其实只要有0和1就ok,其他都是干扰

那么,我们若是1在此位置的话,我们就可以选0,计算后面的排列组合 若是选1的话,则要继续下去

若是在0这个位置的话,则直接计算完

若是大于1的数的话,则当前这位开始,直接开始计算

{Ccntnidxt>1Ccntnidx1+dfs(cnt1,idx+1)t==1dfs(cnt,idx+1)t==0 \begin{cases} C_{cnt}^{n - idx} & t > 1 \\ C_{cnt}^{n - idx - 1} + dfs(cnt - 1, idx+1) & t == 1 \\ dfs(cnt, idx + 1) & t == 0 \end{cases}

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int x, y;
int k, b;
int f[N][N];
void init(){
    for(int i=0; i< N ;i ++)
        for(int j =0; j<= i ;j++)
            if(!j) f[i][j] =1;
            else f[i][j] =f[i-1][j] +f[i-1][j-1];
}
int con(int x, int n) {
  return f[n][x];
}
int fun(int x) {
  vector<int> ve;
  while (x) ve.push_back(x % b), x /= b;
  reverse(begin(ve), end(ve));
  int n = ve.size();
  function<int(int, int)> dfs = [&](int cnt, int idx) -> int {
    if (idx == n) return cnt == 0;
    if (cnt == 0) return 1;
    int t = ve[idx];
    if (t > 1) {
      return con(cnt, n - idx);
    } else if (t == 1) {
      return con(cnt, n - idx - 1) + dfs(cnt - 1, idx + 1);
    } else if (t == 0) return dfs(cnt, idx + 1);
  };
  return dfs(k, 0);
}

int main() {
  cin >> x >> y
      >> k >> b;
  init();
  cout << fun(y) - fun(x-1)<< endl;
  
  return 0;
}