首页 > 其他分享 >Atcoder ABC 333 F - Bomb Game 2

Atcoder ABC 333 F - Bomb Game 2

时间:2023-12-24 15:33:06浏览次数:34  
标签:Atcoder ABC int ll rev Game 炸掉 dp mod

题目大意(采用0#语言):有n个人,每个人每次要么被“炸掉”,要么就被移到最后面去,概率都是1/2,求最后只剩下初始时排名为第i的人的概率。


 

这道题跟人数有关,而且跟位置有关。

我们定义dp[i]表示一共有i个人,第i个为最后一位留下来时的概率。

(不想写公式)

定义j从0到i - 1,表示从前面i - 1个人里面选择j个人“炸掉”

ans[i] = 从i - 1里面选择j个人的方案数  * (1 / 2i) * dp[n - j]

1 / 2i表示每次炸掉前面j个人并且将第i个人移到最后一个去的可能性。那么一共还剩下n - j个人,i在最后面,在乘上这个可能性就可以了。

我们会发现,dp[i]这个神奇的东西,和数量有关,方案数的移动也总是和数有着联系,位置在变,但是数没有变。


我们已经知道如何求解正确的答案了,那么我们接下来怎么求出dp[i]呢?

现在有多种情况

(1)i位置的前面i - 1个数全部都被“炸掉”,也就是说i已经成为剩下的最后一个数字,不能操作了,答案是1 / 2i - 1

(2)i位置前面的i - 1个数一个都没有被炸掉,那么答案就是2i * dp[i](现在i又被移到了最后一个位置上面去)

想到这里,我不禁思考一个问题,就是i永远都不成为最后一个留下的数字,这些操作有可能会一直进行下去,是的,这也是一种概率。硬要我解释的话,可能就是找到那些有尽的概率吧,无穷的概率谁也说不清楚了。

(3)i位置前面i - 1个数字中选出j个数字(1 <= j <= i - 2)炸掉,dp[i] += 从i个数字里面选出j个数字的方案数 * (1 / 2i) * dp[i - j]

我们知道dp[1] = 1, 从i = 2开始dp。

另外对于(2)的情况,dp[i]是未知的,有一种常见的思路,就是把dp[i]进行移项变成 dp[i] * (1 + (...)) = ...的形式,然后把(1 + (...))移到右边去变成除法就可以啦!

#include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const ll mod = 998244353 ;
const int N = 3005 ;
int n ;
ll dp[N], a[N], ni[N], ans[N], er[N], fac[N], rev[N] ;
ll Quick(ll a, int b)
{
    ll res = 1 ;
    while(b)
    {
        if(b & 1) res = res * a % mod ;
        a = a * a % mod ;
        b >>= 1 ;
    }
    return res ;
}
ll C(int a, int b)
{
    if(b == 0) return 1ll ;
    return fac[a] * rev[b] % mod * rev[a - b] % mod ;
}
int main()
{
    scanf("%d", &n) ;
    ni[0] = 1, er[0] = 1 ;
    fac[0] = 1 ;
    for(int i = 1; i <= n; i ++) ni[i] = (ni[i - 1] << 1) % mod, er[i] = (er[i - 1] << 1) % mod, fac[i] = fac[i - 1] * i % mod ;
    for(int i = 1; i <= n; i ++)
    {
        ni[i] = Quick(ni[i] - 1, mod - 2) ;
        er[i] = Quick(er[i], mod - 2) ;
    }    
    rev[n] = Quick(fac[n], mod - 2) ;
    for(int i = n; i >= 1; i --) rev[i - 1] = rev[i] * i % mod ;
    dp[1] = 1 ;
    for(int i = 2; i <= n; i ++)
    {
        dp[i] = 2 * ni[i] % mod ;
        for(int j = 1; j <= i - 2; j ++)
        {
            dp[i] = (dp[i] + C(i - 1, j) * dp[i - j] % mod * ni[i] % mod) % mod ;
        }  
    }
    ans[n] = dp[n] ;
    for(int i = 1; i <= n - 1; i ++)
    {
        for(int j = 0; j <= i - 1; j ++)
        {
            ans[i] = (ans[i] + C(i - 1, j) * er[i] % mod * dp[n - j] ) % mod ;
        }
    }
    for(int i = 1; i <= n; i ++)
    {
        printf("%lld ", ans[i]) ;
    }
    return 0 ;
}
 

 

标签:Atcoder,ABC,int,ll,rev,Game,炸掉,dp,mod
From: https://www.cnblogs.com/ybC202444/p/17924432.html

相关文章

  • AtCoder Beginner Contest 334题解
    ⭐AtCoderBeginnerContest334前言:比赛题目链接--按照惯例只写了主要部分的代码--特别说明:Rust有一个竞赛用的输入库,并且写ABC是可以用的,但是平时写洛谷是用不了的,所以我自己写了一个cin(),凑活能用,代码见下:读输入函数fncin()->String{letmutinput=String......
  • [ABC265F] Manhattan Cafe 题解
    [ABC265F]ManhattanCafe题解思路解析很有思维难度的一道题。思路是dp,\(f[i][j][k]\)表示已经计算了\(i\)维,距离点\(p\)的距离为\(j\),距离点\(q\)的距离为\(k\)时的整点\(r\)个数,由此可见我们的每一维都可以从上一维推出来,也即\(f[i][j][k]\)可以由\(f[i-1][j......
  • ABC334 全套题解
    A-ChristmasPresent简单题。voidslv(){ inta=Read<int>(),b=Read<int>(); if(a>b)Puts("Bat"); elsePuts("Glove"); return;}B-ChristmasTrees也是简单题。constexpri128INF=-1e18;i128a,m,l,r;voidslv(......
  • AtCoder Beginner Contest 334 G Christmas Color Grid 2
    洛谷传送门AtCoder传送门考虑相当于把每个标记点的边全部断掉,然后求连通块个数。考虑一条边\((u,v)\)(设\(u<v\))的出现时间,不难发现是\([1,u-1]\cup[u+1,v-1]\cup[v+1,n]\)。于是考虑直接套线段树分治和可撤销并查集。时空复杂度均为\(O(n^2\logn)\)......
  • 题解 ABC334G【Christmas Color Grid 2】
    先求出初始时绿连通块数量。将一个绿色格子染成红色,会改变绿连通块数量,当且仅当这个绿色格子是孤点或割点。如果是孤点,会使得绿连通块数量减少一;如果是割点,会使得绿连通块数量增加它所在的点双数量减一。根据上述规则可以求出每个绿色格子染红后的绿连通块数量,求平均值即可。时......
  • 题解 ABC334F【Christmas Present 2】
    设\(f_i\)表示假设只有编号为\(1\simi\)的点,此时的答案。\(f_n\)即为所求。显然有:\[f_i=\min\limits_{i-k\lej<i}\{f_j+dis(s\toj+1\toj+2\to\cdots\toi)\}+dis(i\tos)\]当\(i\toi+1\)时,大括号内部全局增加\(dis(i\toi+1)\),可以全局打标记后单调队列维护。......
  • 题解 ABC334E【Christmas Color Grid 1】
    先求出初始时绿连通块数量。枚举每个红色格子,将其染成绿色本应增加一个绿连通块,但是它每与一个绿连通块相邻,就又会减少一个绿连通块。根据上述规则可以求出每个红色格子染绿后的绿连通块数量,求平均值即可。时间复杂度\(O(nm)\)。//Problem:E-ChristmasColorGrid1//Co......
  • AtCoder Beginner Contest 334
    A-ChristmasPresent(abc334A)题目大意给定两个数\(b,g(b\neqg)\),如果\(b\)大则输出Bat,否则输出Glove。解题思路比较大小输出即可。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::sync_with_stdio(f......
  • ABC251G
    提供一个本质相同,但是不需要会向量也能做,而且很好想的方法。首先发现凸包点少,也就意味着边少,考虑从边的方向寻找突破口。考虑一个凸包的本质:若干个直线划分出若干个半平面,它们的交即为这个凸包。如果一个点对于每一条直线,都在于凸包的同侧,那么这个点就在这个凸包内。这样直接暴......
  • ABC321G
    其实赛时可能可以做出来的,只是打了前6道想下班了,有点小小遗憾。首先问题看起来很唬人,考虑转换一下。考虑已经固定\(m\)条边,对于一个集合\(S\),什么时候会不与其他点有边。容易发现,此时需要满足\(\sum[R_i\inS]=\sum[B_j\inS]\)。记这个数为\(c_S\)。但是这还不够,因为\(......