题目链接
题目描述
一个红包总金额为 元,有
个人来抢。规则如下:如果红包里还剩
元,下一个人抢到的金额是从区间
中等概率均匀随机出的一个实数。
求第 个人期望抢到多少钱,结果对
取模。
输入:
- 输入一行,包含三个整数
。
输出:
- 输出一行,表示第
个人期望抢到的钱数对
取模后的结果。
解题思路
这是一个经典的期望问题,可以通过线性递推来解决。
1. 定义状态
- 设
为第
个人抢到的金额(一个随机变量)。
- 设
为第
个人抢红包之前,红包里剩余的金额(也是一个随机变量)。
- 我们要求的是第
个人的期望金额,即
。
2. 分析单次期望
- 根据题目规则,如果红包里有
元,抢到的金额是
上的均匀分布。一个在
上均匀分布的随机变量,其期望值为
。
- 因此,在已知红包剩余
的情况下,第
个人抢到金额的条件期望是
。
3. 建立递推关系
- 根据全期望公式,
。
- 这说明,第
个人的期望金额是抢红包前剩余金额的期望值的一半。
- 接下来,我们分析剩余金额期望
的关系。第
个人抢之前剩余的钱
,等于第
个人抢之前剩余的钱
减去第
个人抢走的钱
。即
。
- 两边取期望,利用期望的线性性质,得到
。
- 将
代入,得到
。
4. 求解通项公式
- 我们得到了一个关于剩余金额期望的递推式:
。
- 初始条件是
(第一个人抢之前,红包里有全部金额)。
- 这是一个等比数列,可以得到通项公式:
。
- 因此,第
个人抢到金额的期望为
。
5. 计算结果
- 我们需要计算
。
- 这等价于计算
。
- 模数
是一个质数,我们可以使用费马小定理来求乘法逆元。对于质数模
,
。
- 一个高效的计算方法是先求出
的逆元
inv2
,然后计算inv2
的次方。
inv2
。
- 最终结果是
。
- 所有幂运算都可以通过快速幂来高效完成。
代码
#include <iostream>
using namespace std;
typedef long long LL;
LL power(LL base, LL exp) {
LL res = 1;
LL mod = 1e9 + 7;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) res = res * base % mod;
base = base * base % mod;
exp /= 2;
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
LL w, n, k;
cin >> w >> n >> k;
LL mod = 1e9 + 7;
// 计算 2 的乘法逆元
LL inv2 = power(2, mod - 2);
// 计算 2^k 的乘法逆元,即 (2的逆元)^k
LL inv2_k = power(inv2, k);
// 期望 = W * (1/2^k)
LL ans = (w * inv2_k) % mod;
cout << ans << endl;
return 0;
}
import java.util.Scanner;
public class Main {
static long power(long base, long exp) {
long res = 1;
long mod = 1_000_000_007;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) res = (res * base) % mod;
base = (base * base) % mod;
exp /= 2;
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long w = sc.nextLong();
long n = sc.nextLong();
long k = sc.nextLong();
long mod = 1_000_000_007;
// 计算 2 的乘法逆元
long inv2 = power(2, mod - 2);
// 计算 2^k 的乘法逆元,即 (2的逆元)^k
long inv2_k = power(inv2, k);
// 期望 = W * (1/2^k)
long ans = (w * inv2_k) % mod;
System.out.println(ans);
}
}
import sys
def power(base, exp):
res = 1
mod = 10**9 + 7
base %= mod
while exp > 0:
if exp % 2 == 1:
res = (res * base) % mod
base = (base * base) % mod
exp //= 2
return res
def main():
w, n, k = map(int, sys.stdin.readline().split())
mod = 10**9 + 7
# 计算 2 的乘法逆元
inv2 = power(2, mod - 2)
# 计算 (1/2)^k
inv2_k = power(inv2, k)
# 期望 = W * (1/2^k)
ans = (w * inv2_k) % mod
print(ans)
if __name__ == "__main__":
main()
算法及复杂度
- 算法:数学期望 + 快速幂求逆元
- 时间复杂度:算法主要由两次快速幂运算构成。一次用于求
的逆元,其指数为
;另一次用于求逆元的
次方。总时间复杂度为
。
- 空间复杂度:只需要常数个变量来存储中间结果,所以空间复杂度为
。