• [蔚来杯]Two Frogs


    题目链接

    题意

    河道里有 n n n个荷叶排成一排,从第 i ( < n ) i(i(<n)个荷叶出发可以跳到第 ( i , i + a i ] (i,i+a_i] (i,i+ai]个荷叶上,有两只青蛙从第 i i i个荷叶出发,每一步都独立地等概率随机地跳向后边的荷叶,求两只青蛙以相同步数到达第 n n n个荷叶的概率。

    n < = 8000 n <= 8000 n<=8000,保证 1 < = a i < = n − i 1 <= a_i <= n - i 1<=ai<=ni

    分析

    这一题的容易联想到使用dp求解,并使用当前荷叶编号已经跳跃的次数确定一个状态。

    但在状态表示时,可能因为能够走到当前状态的次数作为状态表示,导致状态转移难以推算。

    对于本题,最合适的做法是直接记录每个状态的概率。

    f [ i ] [ j ] f[i][j] f[i][j]表示从第1片荷叶跳 j j j次到达 i i i片荷叶的概率

    根据分布乘法原理,易得状态转移方程:
    f [ i + x ] [ j + 1 ] + = f [ i ] [ j ] / a i , ( x < = a i ) f[i+x][j+1] += f[i][j] / a_i,(x <= a_i) f[i+x][j+1]+=f[i][j]/ai(x<=ai)

    进一步,两只青蛙从第 1 1 1片荷叶跳跃 j j j次到达 i i i片荷叶的概率为: f [ i ] [ j ] ∗ f [ i ] [ j ] f[i][j] * f[i][j] f[i][j]f[i][j]
    再根据分类加法原理,两只青蛙以相同的步数到达第 n n n片荷叶的概率为: ∑ x = 1 n − 1 f [ n ] [ x ] \sum_{x=1}^{n-1} f[n][x] x=1n1f[n][x]
    注:青蛙一次跳跃至少前进一个荷叶,所以至多经过 n − 1 n-1 n1次跳跃到达第 n n n片荷叶。

    代码如下:

    #include
    using namespace std;
    const int N = 1e4+10,MOD = 998244353;
    int n,F[N][N],A[N],INV[N];
    int qmi(int a,int b,int p){
        int res = 1;
        a %= p;
        while(b){
            if(b & 1) res = 1ll * res * a % p;
            b >>= 1;
            a = 1ll * a * a % p;
        }
        return res;
    }
    int main(){
        scanf("%d",&n);
        for(int i = 1;i < n;i++) scanf("%d",&A[i]), INV[i] = qmi(A[i],MOD-2,MOD);
        F[1][0] = 1;
        for(int i = 1;i < n;i++)
            for(int j = 0;j <= n-1;j++)
                for(int k = 1;k <= A[i] && i+k <= n;k++)
    //                 F[i+k][j+1] += F[i][j] / A[i];
                    F[i+k][j+1] = (F[i+k][j+1] + 1ll * F[i][j] * INV[i]) % MOD;
        int s = 0;
        for(int i = 1;i <= n-1;i++)
            s = (s + 1ll * F[n][i] * F[n][i]) % MOD;
        printf("%d",s);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    O ( n 3 ) O(n^3) O(n3)的复杂度,TLE。
    需要进行优化。
    这里可以使用差分优化,将复杂度降为 O ( n 2 ) O(n^2) O(n2)

    #include
    using namespace std;
    const int N = 1e4+10,MOD = 998244353;
    int n,F[N][N],A[N],INV[N];
    int qmi(int a,int b,int p){
        int res = 1;
        a %= p;
        while(b){
            if(b & 1) res = 1ll * res * a % p;
            b >>= 1;
            a = 1ll * a * a % p;
        }
        return res;
    }
    int main(){
        scanf("%d",&n);
        for(int i = 1;i < n;i++) scanf("%d",&A[i]), INV[i] = qmi(A[i],MOD-2,MOD);
        F[1][0] = 1;
        F[2][0] = -1;
        for(int i = 1;i <= n;i++)
            for(int j = 0;j <= n;j++){
                F[i][j] = (F[i][j] + F[i-1][j]) % MOD;
                int t = 1ll * F[i][j] * INV[i] % MOD;
                F[i+1][j+1] = (1ll * F[i+1][j+1] + t) % MOD;
                F[i+A[i]+1][j+1] = (1ll * F[i+A[i]+1][j+1] - t) % MOD;
            }
        int s = 0;
        for(int i = 1;i <= n;i++)
            s = (s + 1ll * F[n][i] * F[n][i]) % MOD;
        printf("%d",s);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    这里需要注意,使用的差分为是一维的差分。
    初始情况下, f [ 1 ] [ 0 ] f[1][0] f[1][0] f [ 2 ] [ 0 ] f[2][0] f[2][0]为原 f [ 1 ] [ 0 ] f[1][0] f[1][0] f [ 2 ] [ 0 ] f[2][0] f[2][0]的差分值。
    在计算过程中,数值可能超过int表示范围,通过类型转换方式解决。
    将A数组的逆元进行预处理可减少计算量。

  • 相关阅读:
    多系统电脑切换系统操作步骤
    字节跟踪偷拍前员工到快手上班,告他违反竞业协议,前员工被判赔偿字节30万!...
    海南热带海洋学院金秋悦读《乡村振兴战略下传统村落文化旅游设计》2023新学年许少辉八一新书​
    西瓜视频 iOS 播放器技术重构
    HACKTHEBOX——Shocker
    C 基础知识内容
    算法分析基础
    数据预处理之基于聚类的TOD异常值检测#matlab
    vue3响应式模块的实现 efffect reactive ref...
    readme.md编写并生成html
  • 原文地址:https://blog.csdn.net/qq_35630119/article/details/126457406