• CF1204E Natasha, Sasha and the Prefix Sums [动态规划]


    Natasha, Sasha and the Prefix SumsNatasha, Sasha and the Prefix Sums

    题目描述见链接 .


    color{red}{正解部分}

    F[i,j]F[i, j] 表示 ii11, jj1-1 的答案, 从后往前 放置数字进行 状态转移

    • 放置 11: 对 F[i,j]F[i, j] 产生 F[i1,j]+(i1+ji1)F[i-1, j] + egin{pmatrix} i-1+j \ i-1 end{pmatrix} 的贡献 .

    • 放置 1-1: 对 F[i,j]F[i, j] 产生 F[i,j1]((i+j1j1)g[i,j1])F[i, j-1] - left( egin{pmatrix} i+j-1 \ j-1 end{pmatrix} - g[i, j-1] ight) 的贡献 .

    • 初值: F[i,0]=iF[i, 0] = i

    其中 g[i,j]g[i, j] 表示 ii11, jj1-1 所组成的序列 最大前缀和00 的方案数, 先考虑特殊情况,

    • i>ji > j, g[i,j]=0g[i, j] = 0 .
    • g[0,0]=1g[0, 0] = 1

    再考虑 iji le j 时, g[i,j]g[i, j] 能更新哪些状态,

    • 11 时, 若能更新 g[i+1,j]g[i+1, j], 则说明 i<ji < jiji le j, 所以转移条件为 i<ji < j .
    • 1-1 时, 若能更新 g[i,j+1]g[i, j+1], 则说明 iji le jij+1i le j+1, 所以转移条件为 iji le j .

    ij herefore i le j 时, g[i,j]=g[i1,j]+g[i,j1]g[i, j] = g[i-1, j] + g[i, j-1] .

    因为 i1<ji-1 < j, g[i1,j]g[i-1, j] 一定是由于取 maxmax 取到 00 的,
    而原本最大前缀和为 00, 多放置一个 1-1, 最大前缀和仍为 00,
    因此当 iji le j 时, 放置 11 和 放置 1-1 都可以转移到 g[i,j]g[i, j] .


    O(N)O(N) 做法

    这里咕掉了 …

    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 2e6 + 5;
    const int mod = 998244853;
    
    int N;
    int M;
    int Ans;
    int f[maxn];
    int fac[maxn];
    int inv[maxn];
    int ifac[maxn];
    
    int C(int n, int m){ if(n < m) return 0; return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; }
    
    int main(){
            fac[0] = 1; for(reg int i = 1; i < maxn; i ++) fac[i]=1ll*fac[i-1]*i%mod;
            inv[1] = 1; for(reg int i = 2; i < maxn; i ++) inv[i] = ((-1ll*mod/i*inv[mod%i])%mod + mod) % mod;
            ifac[0] = 1; for(reg int i = 1; i < maxn; i ++) ifac[i] = 1ll*ifac[i-1]*inv[i] % mod;
            scanf("%d%d", &N, &M);
            for(reg int i = N; i; i --){
                    if(M+i <= N) f[i] = C(N+M, N);
                    else f[i] = C(N+M, M+i);
                    int add = (f[i]-f[i+1] + mod) % mod;
                    add = 1ll*add*i % mod; 
                    Ans = (Ans + add) % mod;
            }
            printf("%d
    ", Ans);
            return 0;
    }
    

    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 4005;
    const int mod = 998244853;
    
    int N;
    int M;
    int inv[maxn];
    int fac[maxn];
    int ifac[maxn];
    int F[maxn][maxn];
    int g[maxn][maxn];
    
    int C(int n, int m){ return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; }
    
    int main(){
            scanf("%d%d", &N, &M);
            inv[1] = 1; for(reg int i = 2; i < maxn; i ++) inv[i] = ((-1ll*mod/i*inv[mod%i])%mod + mod) % mod;
            fac[0] = 1; for(reg int i = 1; i < maxn; i ++) fac[i] = 1ll*fac[i-1]*i%mod;
            ifac[0] = 1; for(reg int i = 1; i < maxn; i ++) ifac[i] = 1ll*ifac[i-1]*inv[i] % mod;
            g[0][0] = 1;
            for(reg int i = 0; i <= N; i ++)
                    for(reg int j = i; j <= M; j ++){
                            if(i < j) g[i+1][j] = (g[i+1][j] + g[i][j]) % mod;
                            if(i <= j) g[i][j+1] = (g[i][j+1] + g[i][j]) % mod;
                    } 
            for(reg int i = 1; i <= N; i ++) F[i][0] = i;
            for(reg int i = 0; i <= N; i ++)
                    for(reg int j = 1; j <= M; j ++){
                            int add =  (F[i][j-1] - ((C(i-1+j, j-1)-g[i][j-1])%mod+mod)%mod + mod) % mod;
                            F[i][j] = (F[i][j] + add) % mod;
                            if(!i) continue ;
                            add = (F[i-1][j] + C(i-1+j, i-1)) % mod;
                            F[i][j] = (F[i][j] + add) % mod;
                    }
            printf("%d
    ", F[N][M]);
            return 0;
    }
    
  • 相关阅读:
    QT解析和组装json
    linux下磁盘存储空间不足
    linux下的QT打包方法
    linux下编译protobuf
    linux下编译opencv
    linux下的qt串口通信
    QT执行shell脚本及linux指令相关
    windows下QT打包
    启动zookeeper却没有进程
    Linux命令
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822414.html
Copyright © 2020-2023  润新知