京东笔试真题 - 以弱胜强的秘密(C++/Py/Java /Js/Go)

以弱胜强的秘密

京东技术岗 8月8号笔试 第二题

题目内容

在一场单败淘汰赛中,共有 N=2mN = 2^mN=2m 名选手参加。他们的能力值恰好是 111 到 NNN 的每一个整数,没有重复。比赛采用固定的淘汰规则:

  1. 首先,将所有选手按照某种初始顺序排成一行。
  2. 每一轮,将当前序列中相邻的两人配对对战:第 111 名对第 222 名,第 333 名对第 444 名,以此类推。
  3. 若能力值为 xxx 的选手与能力值为 yyy 的选手对战,则 xxx 获胜的概率为 xx+y\frac{x}{x+y}x+yx。
  4. 每轮结束后,胜者保持原有相对顺序,形成新的序列,继续下一轮,直至产生唯一的冠军。
    现在,你希望能力值为 111 的选手获得最终冠军的概率尽可能大。请问:在所有可能的初始排列中,有多少种排列方式可以使得能力值为 111 的选手的夺冠概率达到最大值?答案请对 998244353998244353998244353 取模。
    数据范围:mmm 满足 1≤m≤121 \le m \le 121≤m≤12。

输入描述

输入包含一行一个整数 mmm(1≤m≤121 \le m \le 121≤m≤12),表示选手总数为 2m2^m2m。

输出描述

输出一行一个整数,表示满足条件的初始排列数量对 998244353998244353998244353 取模后的结果。

样例1

输入

复制代码
1

输出

复制代码
2

说明

当 m=1m=1m=1 时,总选手数 N=21=2N=2^1=2N=21=2,能力值为 12。无论怎样排列,能力值为 1 的选手夺冠概率均为 11+2=13\frac{1}{1+2}=\frac{1}{3}1+21=31,即所有 2!=22! = 22!=2 种排列都能使夺冠概率达到最大值。因此答案为 2

样例2

输入

复制代码
3

输出

复制代码
128

说明

总选手数 N=23=8N=2^3=8N=23=8。要使能力值为 1 的选手夺冠概率最大,必须使其在每一轮中对阵的对手尽可能弱。可以证明,满足条件的初始排列总数为 2N−1=27=1282^{N-1}=2^7=1282N−1=27=128。对 998244353998244353998244353 取模后仍为 128

样例3

输入

复制代码
4

输出

复制代码
32768

说明

总选手数 N=24=16N=2^4=16N=24=16。同理,最优排列数量为 2N−1=215=327682^{N-1}=2^{15}=327682N−1=215=32768,取模后结果为 32768

思路

解题思路: 数学原理 + 逻辑分析

  1. 最佳答案就为2^(N - 1), 其中N = 2^m,然后对 998244353取模即可。

    1. 为了让1最终获胜概率最大,较强的选手尽量在1到达它们之前相互比赛。以m=3为例子,期待的比较方式为

      复制代码
                   冠军
                    ●
                  /   \
                 ●     ●
               /  \   /  \
              ●   ●  ●   ●
             / \ / \/ \ / \
            1  2 3 4 5 6 7 8
  2. 可以很容易看出比较过程为完全二叉树,并且二叉树的叶子节点数量为N, 对于完全二叉树,内部节点数量为N-1, 并且每个内部节点左节点和右节点可以交换顺序,不影响最终结果,那么方案数就为2^(N-1)

  3. 2^(N-1)可使用快速幂算法。

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

using ll = long long;
const ll MOD = 998244353;

ll qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int m;
    cin >> m;

    int N = 1 << m;

    // 最优排列对应一棵完全二叉树
    // 每个内部节点的左右子树可以交换
    // N 个叶子共有 N-1 个内部节点
    // 因此答案为 2^(N-1)
    cout << qpow(2, N - 1) << '\n';

    return 0;
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    static final long MOD = 998244353L;

    static long qpow(long a, long b) {
        long res = 1;
        while (b > 0) {
            if ((b & 1) != 0) {
                res = res * a % MOD;
            }
            a = a * a % MOD;
            b >>= 1;
        }
        return res;
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int m = Integer.parseInt(br.readLine().trim());

        int N = 1 << m;

        // 最优排列对应一棵完全二叉树
        // 每个内部节点的左右子树可以交换
        // N 个叶子共有 N-1 个内部节点
        // 因此答案为 2^(N-1)
        System.out.println(qpow(2, N - 1));
    }
}

python

python 复制代码
import sys

MOD = 998244353


def qpow(a, b):
    res = 1
    while b:
        if b & 1:
            res = res * a % MOD
        a = a * a % MOD
        b >>= 1
    return res


m = int(input())

N = 1 << m

# 最优排列对应一棵完全二叉树
# 每个内部节点的左右子树可以交换
# N 个叶子共有 N-1 个内部节点
# 因此答案为 2^(N-1)
print(qpow(2, N - 1))

javascript

js 复制代码
const readline = require("readline");

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

const MOD = 998244353n;

function qpow(a, b) {
    let res = 1n;

    while (b > 0) {
        if (b & 1) {
            res = res * a % MOD;
        }

        a = a * a % MOD;
        b = Math.floor(b / 2);
    }

    return res;
}

rl.on("line", (line) => {
    const m = Number(line.trim());

    const N = 1 << m;

    // 最优排列对应一棵完全二叉树
    // 每个内部节点的左右子树可以交换
    // N 个叶子共有 N-1 个内部节点
    // 因此答案为 2^(N-1)
    console.log(qpow(2n, N - 1).toString());

    rl.close();
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

const MOD int64 = 998244353

func qpow(a, b int64) int64 {
	var res int64 = 1

	for b > 0 {
		if b&1 != 0 {
			res = res * a % MOD
		}

		a = a * a % MOD
		b >>= 1
	}

	return res
}

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var m int
	fmt.Fscan(in, &m)

	N := 1 << m

	// 最优排列对应一棵完全二叉树
	// 每个内部节点的左右子树可以交换
	// N 个叶子共有 N-1 个内部节点
	// 因此答案为 2^(N-1)
	fmt.Fprintln(out, qpow(2, int64(N-1)))
}
相关推荐
无限码力10 小时前
京东笔试真题 - 失落的宝石(C++/Py/Java /Js/Go)
京东·京东笔试真题·京东技术岗笔试真题·京东笔试·京东机试
电商API_180079052472 天前
京东商品详情API技术解析:数据结构、调用实践与系统集成方案
python·api·跨境电商·京东·商品详情
加油20195 个月前
京东人事管理8项规定
管理·京东·8项规定
Cyril_KI2 年前
京东 2025届秋招 自然语言处理
自然语言处理·京东·面试经验·2025届校招
亿牛云爬虫专家2 年前
CSV文件自动化生成:用Pandas与Datetime高效处理商品信息
运维·pandas·爬虫代理·电商·代理ip·datetime·京东
27669582922 年前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
junjie xu2 年前
内推|京东|后端开发|运维|算法...|北京 更多岗位扫内推码了解,直接投递,跟踪进度
京东云·内推·京东
志远19972 年前
笔试算法-编程练习-01-J-24
数据结构·python·算法·京东·大厂笔试
Luca_kill2 年前
Python爬虫实战之爬取京东商品数据
爬虫·python·京东