概率论
n n n 个人进行游戏,每个人初始有 a i a_i ai 个硬币,每次随机选择一个人给另一个人一枚硬币
若某人给出硬币后没有剩余,则退出游戏。直到有人拿到所有硬币游戏结束
求游戏轮数的数学期望
概率论还没学()官方题解的鞅论看不懂(躺)//
等学完回来给严格推导(手搓大饼ing)
ACMer三大美德:暴力、打表、猜结论//下面给出道德解法()
假设现在只有两个人,那么每个人给对方硬币的概率都为50%,直到其中一人没有硬币为止。
设这两个人的硬币数分别为 m , n m,n m,n ,则游戏轮数期望为:
f ( m , n ) = 1 + 1 2 f ( m + 1 , n − 1 ) + 1 2 f ( m − 1 , n + 1 ) f(m,n)=1+\dfrac{1}{2}f(m+1,n-1)+\dfrac{1}{2}f(m-1,n+1) f(m,n)=1+21f(m+1,n−1)+21f(m−1,n+1)
可以发现越往后对期望的贡献越低,限制递归深度,利用如下程序暴力打表:
double f(ll m,ll n,ll rnd){
if(rnd>40) return 0;//递归上限40层(已经要跑很久了)
if(m==0||n==0) return 0;
return 1+0.5*f(m+1,n-1,rnd+1)+0.5*f(m-1,n+1,rnd+1);
}
void solve()
{
ll n,m;cin >> n >> m;
cout << f(m,n,0) << endl;
}
得到以下打表结果(不得不说跑的是真慢):
in:1 3 out:3
in:1 5 out:4.98732
in:2 3 out:5.99897
in:2 5 out:9.8626
in:3 4 out:11.8287
暴力打完表可以猜结论了: f ( m , n ) = m n f(m,n)=mn f(m,n)=mn ,即对于两个人,答案是他们硬币数的乘积;
那么对于三个人,利用样例in:1 1 1 out:3
盲猜是 a 1 a 2 + a 1 a 3 + a 2 a 3 a_1a_2+a_1a_3+a_2a_3 a1a2+a1a3+a2a3
推广到 n n n 个人,两两相乘再相加即可
由于数据较大,答案需要开int128才能放得下
另外结合数据范围,利用前缀和算出结果即可
前缀和&求和: O ( n ) O(n) O(n)
参考代码为已AC代码主干,其中部分功能需读者自行实现
void solve()
{
int128 res;
ll n,t;cin >> n;
vector v(n+1),sum(n+1,0);
FORLL(i,1,n){
cin >> v[i];
sum[i]=v[i]+sum[i-1];
}
FORLL_rev(i,n,1){
res=res+sum[i-1]*v[i];
}
res.print();printf("\n");
return;
}