成都day3t1

9 篇文章 0 订阅
1 、B B  君的第一题 ( beijing .pas/cpp )
【问题描述】
天台上的朋友让一让,让我先来。
世界杯开始了,B 君最近在关注一局季后赛。
在这局季后赛中,甲队和乙队将会进行至多 2n-1 场比赛,谁先取得 n 场胜利,谁
便会获得最终的胜利。并且之后的比赛不会继续进行。
B 君很看好甲队,为了计算方便,B 君希望下注 2
2n-1 元,也就是说,
如果最终甲队先取得了 n 场胜利,B 君就会获得 2
2n-1 元。
如果最终乙队先取得了 n 场胜利,B 君就会失去 2
2n-1 元。
但是事不如人愿,甲队和乙队水平旗鼓相当,每一场比赛,双方胜利的概率都是
0.5,并且所有比赛的结果相互独立。
B 君对此坦然接受,认为自己获得 2
2n-1 元的概率是 0.5,失去 2 2n-1 元的概率是 0.5,
期望收益是 0。
但是赌场的庄家并不允许这样做,必须每一场比赛单独下注,分别进行结算。
B 君很失望,但是他发现,存在唯一一种下注方式,达到自己最初的目的。
即如果最终甲队获胜,B 君各场的收益之和为 2
2n-1 ,如果最终乙队获胜,B 君各场
收益之和为-2
2n-1 。
比如对于 n=2 来说,B 君可以选择在第一场下注 4 元,在第二场下注 4 元,在第三
场下注 8 元。
这样如果甲队或乙队赢了前两场,B 君直接获得或失去了 8 元。
如果前两场甲乙一胜一负,那么 B 君不赔不赚,决胜局下注 8 元。
也就是说,无论甲以什么方式获胜,B 君都会获得 8 元。无论乙以什么方式获胜,
B 君都会失去 8 元。
特别的,B 君可以在看到前 i 场的结果之后,再给出第 i+1 场的下注,而不需要一
开始就给出所有场的下注情况。
对于输入输出,B 君会先告诉你 n,然后你来告诉 B 君第一场比赛应该如何下注,
接下来 B 君告诉你第一场的结果。
你来告诉 B 君第二场比赛应该如何下注,依次类推。如果 B 君告诉你的结果已经导
致了甲队或者乙队取得了 n 场胜利。
你不需要对这次结果做任何回复。
因此你输出的数字个数,和 B 君告诉你比赛结果的个数相同。
你可以下注负数,表示下注乙队获胜,这样如果甲队失败便可获得回报。
这并不是一个交互题,每个回答的答案是唯一的。
【输入格式】
第一行一个数字 n,即上文中所描述的 n。
第二行是一些 0 和 1,如果是 0 表示甲队获胜,1 表示乙队获胜。
保证这是一个合法的比赛过程,也就是说,当出现 0 的个数或 1 的个数达到 n 个之后,

便不会有更多输入了。

【输出格式】
输出若干个数字,一行一个。个数和输入的第二行数字个数相同,表示每场比赛的下注。
由于下注可能很大,你只需要输出模 1000000007 的结果即可。
即使想下注负数,也应该输出取模后的正余数。
可以证明下注的金额一定是整数。
可以证明解是唯一的。
【输入样例】
3
1 1 0 0 1
【输出样例】
12
12
8
16
32
【样例说明】
显然所有下注的和,要么是+2
2n-1 ,要么是-2 2n-1 。对于这场
(-12) + (-12) + (8) + (16) + (-32) = -32 = -2
5
【输入样例】
3
0 1 0 0
【输出样例】
12
12
16
16
【样例说明】
(12) + (-12) + (16) + (16) = 32 = 2
5
你可以根据前两场的结果,来动态的决定第三场的下注。
输入的第二行长度并不确定,当输入 n 个 0 或 n 个 1 时结束。
【数据范围】
对于 100%的数据,满足 1 ≤ n ≤ 100000。
对于 70%的数据,满足 1 ≤ n ≤ 1000。
对于 30%的数据,满足 1 ≤ n ≤ 6。

数据非常有梯度。

分析:

1.1 题目大意
大概是一个比较有趣的面试题。
1.2 题目分析
首先考虑如何计算当前的胜率。
这个有两种算法,动态规划和组合数。
1.3 动态规划
假设当前甲赢了 i 场,⼄赢了 j 场。
如果 i = n,那么 f i,j = 1。
如果 j = n,那么 f i,j = 0。
对于一般情况,有 f i,j =
 (fi + 1,j + f i,j+1 )/2。
可以换一种方法表示,设当前胜率为 p。
如果下一场比赛甲赢了,胜率会变成 p + q。
如果下一场比赛甲输了,胜率会变成 p − q。
即胜率的增加量和减少量⼀样。
这场比赛应该下注 2q × 2 2n−1 。
这样如果胜率增加就赢钱,胜率减少就输钱。
如果胜率从 1/2 增加到 1,就会赢 2 2n−1 。
如果胜率从 1/2 减少到 1,就会输 2 2n−1 。
换句话说,当前剩余钱数,是由胜率决定的。
胜率为 1/2,钱数为 0。
胜率为 1,钱数为 2^(2n−1) 。
胜率为 0,钱数为 −2^(2n−1) 。

对于一般情况胜率 1/2 + q,钱数为 2q × 2^(2n−1) 。

这样你便可以写出一个n^2的算法。

1.4 组合数
核心问题就是,当前甲赢了 i 场,乙赢了 j 场,甲的胜率是多少。
不妨假设没有提前结束的情况,剩下的 t = 2n − 1 − i − j 场比赛一定
打完。
如果甲在其中赢了 n − i 场或更多,甲就获胜了,所以甲的胜率是1个
组合数的求和

这个不是很容易解决。
如果下一场甲赢了,胜率变为

如果下一场甲输了,胜率变为

两者求和中只差一个

带入动态规划的结论,答案是

所以统计前缀中,甲赢得次数 i,乙赢的次数 j。
然后计算组合数和 2 的次幂即可。
组合数的计算可以预处理,或者是利⽤相邻两项只需要乘一项和除一
项来计算。
可以了解一下 O(n) 求 1 到 n 的逆元。
1.5 参考资料
150 Most Frequently Asked Questions on Quant Interviews
Chapter 2.7 Brainteasers, Question 20.

(Answer: Chapter 3.7 Brainteasers, Question 20.)

下面给出标程:

#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() {
freopen("beijing.in","r",stdin);
freopen("beijing.out","w",stdout);
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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值