题解 | #1008.Coins# 2023杭电暑期多校9

1008.Coins

概率论

题目大意

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,n1)+21f(m1,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;
}

你可能感兴趣的:(2023杭电多校,c++)