【华为OD机考 统一考试机试】不含101的数(C++ Java JavaScript Python )

395 阅读7分钟

华为OD机考:统一考试 C卷 + D卷 + B卷 + A卷

2023年11月份,华为官方已经将 华为OD机考:OD统一考试(A卷 / B卷)切换到 OD统一考试(C卷)和 OD统一考试(D卷) 。根据考友反馈:目前抽到的试卷为B卷或C卷/D卷,其中C卷居多 ,按照之前的经验C卷部分考题会复用A卷,B卷题,博主正积极从考过的同学收集C卷和D卷真题。 可以先继续刷B卷, C卷和D卷的题目会放在现在大家购买的专栏内,不需要重新购买,请大家放心。

专栏:2023华为OD机试( A卷+B卷+C卷+D卷)(C++JavaJSPy)

华为OD面试真题精选:华为OD面试真题精选

在线OJ:点击立即刷题,模拟真实机考环境

华为OD机考B卷C卷华为OD机考华为OD机考B卷华为OD机试B卷华为OD机试C卷华为OD机考C卷华为OD机考D卷题目华为OD机考C卷/D卷答案华为OD机考C卷/D卷解析华为OD机考C卷和D卷真题华为OD机考C卷和D卷题解

题目描述

小明在学习二进制时,发现了一类不含 101的数,也就是:

将数字用二进制表示,不能出现 101 。
现在给定一个整数区间 [l,r] ,请问这个区间包含了多少个不含 101 的数?

输入描述

输入的唯一一行包含两个正整数 l, r( 1 ≤ l ≤ r ≤ 10^9)。

输出描述

输出的唯一一行包含一个整数,表示在 [l,r] 区间内一共有几个不含 101 的数。

用例

输入1 10
输出8
说明区间 [1,10] 内, 5 的二进制表示为 101 ,10的二进制表示为 1010 ,因此区间 [ 1 , 10 ] 内有 10−2=8 个不含 101的数。
输入10 20
输出7
说明区间 [10,20] 内,满足条件的数字有 [12,14,15,16,17,18,19] 因此答案为 7。

题目解析

本题乍看是很简单的题目,直接进制转换,暴力法不就得了。但是你注意看范围是【1 ≤ l ≤ r ≤ 10^9】,暴力肯定会超时。这题使用的是数位DP

数位dp总结 之 从入门到模板_wust_wenhao的博客-CSDN博客

代码思路

这道题可以使用数位DP来解决。具体思路是从高位到低位逐位枚举,对于每一位,枚举它的取值,并根据前一位和前两位的值来判断是否符合条件。同时,使用记忆化数组来避免重复计算。

具体实现中,可以将数字转换为二进制数,然后递归处理每一位。递归函数中,p表示当前处理到的二进制位,limit表示当前位是否受到上限制,f表示记忆化数组,arr表示二进制数,pre表示前一位的值,prepre表示前两位的值。递归结束条件是处理完所有二进制位,此时返回1。在递归过程中,统计符合条件的数的个数,并使用记忆化数组避免重复计算。

最终,可以通过调用countBinaryWithout101函数来统计区间[L, R]内不含101的数的个数,具体实现中,使用countBinaryWithout101(R) - countBinaryWithout101(L - 1)来统计。

C++

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
// 递归函数,p表示当前处理到的二进制位,limit表示当前位是否受到上限制,f表示记忆化数组,arr表示二进制数,pre表示前一位的值,prepre表示前两位的值
int dfs(int p, bool limit, int f[][2][2], vector<int>& binary, int pre, int prepre) {
    // 当处理完所有二进制位时,返回1
    if (p == binary.size()) return 1;

    // 如果当前位没有受到上限制,则可以使用记忆化数组
    if (!limit && f[p][pre][prepre] != 0) return f[p][pre][prepre];

    // 当前位的最大值
    int max_val = limit ? binary[p] : 1;
    int count = 0;

    // 枚举当前位的值
    for (int i = 0; i <= max_val; i++) {
        // 如果当前位为1,且前一位和前两位都为0,则不符合条件
        if (i == 1 && pre == 0 && prepre == 1) continue;
        // 统计符合条件的数的个数
        count += dfs(p + 1, limit && i == max_val, f, binary, i, pre);
    }

    // 如果当前位没有受到上限制,则可以使用记忆化数组
    if (!limit) f[p][pre][prepre] = count;

    return count;
}

int countBinaryWithout101(int num) {
    // 将数字转换为二进制数
    vector<int> binary;
    while (num > 0) {
        binary.push_back(num % 2);
        num /= 2;
    }
    reverse(binary.begin(), binary.end());

    // 初始化记忆化数组
    int f[binary.size()][2][2];
    memset(f, 0, sizeof(f));

    // 统计不含101的数的个数
    return dfs(0, true, f, binary, 0, 0);
}

int main() {
    int L, R;
    cin >> L >> R;

    // 统计区间[L, R]内不含101的数的个数
    int count = countBinaryWithout101(R) - countBinaryWithout101(L - 1);
    cout << count << endl;

    return 0;
}

JavaScript

function dfs(p, limit, f, binary, pre, prepre) {
  if (p === binary.length) return 1;

  if (!limit && f[p][pre][prepre] !== 0) return f[p][pre][prepre];

  const max_val = limit ? binary[p] : 1;
  let count = 0;

  for (let i = 0; i <= max_val; i++) {
    if (i === 1 && pre === 0 && prepre === 1) continue;
    count += dfs(p + 1, limit && i === max_val, f, binary, i, pre);
  }

  if (!limit) f[p][pre][prepre] = count;

  return count;
}

function countBinaryWithout101(num) {
  const binary = [];
  while (num > 0) {
    binary.push(num % 2);
    num = Math.floor(num / 2);
  }
  binary.reverse();

  const f = Array.from(Array(binary.length), () =>
    Array.from(Array(2), () => Array.from(Array(2), () => 0))
  );

  return dfs(0, true, f, binary, 0, 0);
}

const readline = require('readline');
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.on('line', (input) => {
  const [L, R] = input.split(' ').map(Number);
  const count = countBinaryWithout101(R) - countBinaryWithout101(L - 1);
  console.log(count);
});

Java

import java.util.*;

public class Main {
    // 递归函数,p表示当前处理到的二进制位,limit表示当前位是否受到上限制,f表示记忆化数组,arr表示二进制数,pre表示前一位的值,prepre表示前两位的值
    public static int dfs(int p, boolean limit, int[][][] f, List<Integer> binary, int pre, int prepre) {
        // 当处理完所有二进制位时,返回1
        if (p == binary.size()) return 1;

        // 如果当前位没有受到上限制,则可以使用记忆化数组
        if (!limit && f[p][pre][prepre] != 0) return f[p][pre][prepre];

        // 当前位的最大值
        int max_val = limit ? binary.get(p) : 1;
        int count = 0;

        // 枚举当前位的值
        for (int i = 0; i <= max_val; i++) {
            // 如果当前位为1,且前一位和前两位都为0,则不符合条件
            if (i == 1 && pre == 0 && prepre == 1) continue;
            // 统计符合条件的数的个数
            count += dfs(p + 1, limit && i == max_val, f, binary, i, pre);
        }

        // 如果当前位没有受到上限制,则可以使用记忆化数组
        if (!limit) f[p][pre][prepre] = count;

        return count;
    }

    public static int countBinaryWithout101(int num) {
        // 将数字转换为二进制数
        List<Integer> binary = new ArrayList<>();
        while (num > 0) {
            binary.add(num % 2);
            num /= 2;
        }
        Collections.reverse(binary);

        // 初始化记忆化数组
        int[][][] f = new int[binary.size()][2][2];

        // 统计不含101的数的个数
        return dfs(0, true, f, binary, 0, 0);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int L = scanner.nextInt();
        int R = scanner.nextInt();

        // 统计区间[L, R]内不含101的数的个数
        int count = countBinaryWithout101(R) - countBinaryWithout101(L - 1);
        System.out.println(count);
    }
}

Python

def dfs(p, limit, f, binary, pre, prepre):
    # 如果已经到达二进制数的最高位,返回 1
    if p == len(binary):
        return 1

    # 如果不需要枚举,直接返回 f 数组中已经存储的值
    if not limit and f[p][pre][prepre] != 0:
        return f[p][pre][prepre]

    # 如果需要枚举,记录当前位的最大值
    max_val = binary[p] if limit else 1
    count = 0

    # 枚举当前位的值
    for i in range(max_val + 1):
        # 如果当前位为 1,且前两位为 10,则跳过
        if i == 1 and pre == 0 and prepre == 1:
            continue
        # 统计不含 101 的数的个数
        count += dfs(p + 1, limit and i == max_val, f, binary, i, pre)

    # 如果不需要枚举,将统计结果存入 f 数组中
    if not limit:
        f[p][pre][prepre] = count

    return count


# 定义计算不含 101 的数的个数的函数
def countBinaryWithout101(num):
    # 将整数转换成二进制数
    binary = []
    while num > 0:
        binary.append(num % 2)
        num //= 2
    binary.reverse()

    # 定义一个三维数组存储已经计算过的结果
    f = [[[0 for _ in range(2)] for _ in range(2)] for _ in range(len(binary))]
    # 调用深度优先搜索函数,返回不含 101 的数的个数
    return dfs(0, True, f, binary, 0, 0)


# 读取输入的两个整数
L, R = map(int, input().split())
# 计算区间 [L,R] 内不含 101 的数的个数
count = countBinaryWithout101(R) - countBinaryWithout101(L - 1)
# 输出结果
print(count)

@[TOC]

doutub_gif