B君的第一题
1.1 题目大意
大概是个比较有趣的面试题。
1.2 题目分析
首先考虑如何计算当前的胜率。 这个有两种算法,动态规划和组合数。
1.3 动态规划
假设当前甲赢了 i 场,乙赢了 j 场。 如果 i = n,那么 fi,j = 1。 如果 j = n,那么 fi,j = 0。 对于一般情况,有 fi,j = 1 2 (fi+1,j + fi,j+1)。 可以换一种方法表示,设当前胜率为 p。 如果下一场比赛甲赢了,胜率会变成 p + q。 如果下一场比赛甲输了,胜率会变成 p − q。 即胜率的增加量和减少量一样。 这场⽐赛应该下注 2q × 2 2n−1。 这样如果胜率增加就赢钱,胜率减少就输钱。 如果胜率从 1/2 增加到 1,就会赢 2 2n−1。 如果胜率从 1/2 减少到 0,就会输 2 2n−1。 换句话说,当前剩余钱数,是由胜率决定的。 胜率为 1/2,钱数为 0。 胜率为 1,钱数为 2 2n−1。 胜率为 0,钱数为 −2 2n−1。 对于⼀般情况胜率 1/2 + q,钱数为 2q × 2 2n−1。这样你便可以写出一个 O(n²) 的做法。
1.4 组合数
要预处理组合数和2的次幂。
#include <bits/stdc++.h> using namespace std; int n, x, y, o, p = 1000000007; int v[2000020]; long long C(int n, int m) { long long re = 1; for (int i = 0; i < m; i++) { re = re * (n - i) % p * v[i + 1] % p; } return re; } int main() { scanf("%d", &n); v[1] = 1; for (int i = 2; i < 2 * n; i++) { v[i] = (long long)v[p % i] * (p - p / i) % p; } x = y = n; long long z = C(x + y - 2, x - 1) * 2 % p; while (x > 0 && y > 0) { printf("%lld\n", z); scanf("%d", &o); z = z * 2 * v[x + y - 2] % p; if (o == 0) { z = z * (--x) % p; } else { z = z * (--y) % p; } } return 0; }