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;
}
View Code

 

 

 

 

 

posted @ 2018-08-14 16:50  滑稽的大白兔  阅读(265)  评论(0编辑  收藏  举报