zoukankan      html  css  js  c++  java
  • [CF1204E]Natasha,Sasha and the Prefix Sums 题解

    前言

    本文中的排列指由n个1, m个-1构成的序列中的一种。
    题目这么长不吐槽了,但是这确实是一道好题。

    题解

    DP题话不多说,直接状态/变量/转移。

    状态

    我们定义f表示"最大prefix sum"之和

    变量

    f[i][j]为有i个1,j个-1的"最大prefix sum"之和

    转移

    我们记C[i][j]为(left(egin{matrix} i \ jend{matrix} ight)),那么:

    [f[i][j] = left{egin{matrix} f[i-1][j]+1 imes C[i+j-1][i-1] \ f[i][j-1]+(-1) imes(C[i+j-1][j-1]-k[i][j-1])end{matrix} ight. ]

    k[i][j]表示有i个1,j个-1的最大前缀和刚好为0的排列的个数
    那么上式是如何推出的呢?
    我们固定地认为每当新加入一个数的时候将该数插入序列的最前方,这种设定仍然保证了动规涵盖所有珂能的排列。
    如果我们插入的是一个1,不管先前的序列排列如何,最大prefix sum一定会加1,由于i-1个1,j个-1对应的序列有(left(egin{matrix} i+j-1 \ iend{matrix} ight))种排列方法,所以当前状态增加的贡献为(left(egin{matrix} i+j-1 \ iend{matrix} ight))
    如果我们插入的是一个-1,情况于上面是完全相同的,但是注意到,如果有一种排列它本身的"最大prefix sum"为0,那么我们不应当把它计入贡献(因为"最大prefix sum"最小为0),所以要减去k[i][j]。
    组合数显然珂以通过杨辉三角递推解决。
    那么现在我们的问题就在于k[i][j]如何处理。
    我们先给出k[i][j]的递推式。

    [k[i][j]=left{egin{matrix}i=0 & k[i][j]=1 \ j=0 & k[i][j]=0 \ i > j & k[i][j]=0 \ ext{其余情况} & k[i][j]=k[i-1][j]+k[i][j-1]end{matrix} ight. ]

    这个递推式珂能有点晦涩,但是一种简单的理解方式是找出由当前状态向外转移的方程式,然后再转化为以上方程式。
    于是我们解决了此题。

    代码

    没有卡常,见谅。

    #include <cstdio>
    #define MOD 998244853
    
    long long f[2005][2005];
    long long k[2005][2005];
    long long C[4005][4005];
    
    int main(){
        int n, m; scanf("%d %d", &n, &m);
        for (register int i = 0; i <= n; ++i)
            for (register int j = 0; j <= m; ++j){
                if (i == 0) k[i][j] = 1;
                else if (j == 0) k[i][j] = 0;
                else if (i > j) k[i][j] = 0;
                else k[i][j] = (k[i - 1][j] + k[i][j - 1]) % MOD;
            }
        C[0][0] = C[1][0] = C[1][1] = 1;
        for (register int i = 2; i <= n + m; ++i){
            C[i][0] = 1;
            for (register int j = 1; j <= i; ++j)
                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
        }
        for (register int i = 0; i <= n; ++i)
            f[i][0] = i, f[0][i] = 0;
        for (register int i = 1; i <= n; ++i)
            for (register int j = 1; j <= m; ++j)
                f[i][j] = ((f[i - 1][j] + C[i + j - 1][i - 1]) % MOD + (f[i][j - 1] - C[i + j - 1][j - 1] + k[i][j - 1] + MOD) % MOD) % MOD;
        printf("%I64d", f[n][m]);
        return 0;
    }
    
  • 相关阅读:
    event对象之与onmouse相关的事件触发
    对文档树进行导航
    event对象的onkeydown使用
    event的onchange方法
    函数名-函数参数坑-迭代器
    函数进阶-名称空间
    初识函数
    文件管理
    基础数据类型补充-编码进阶
    集合-缓存机制-深浅copy
  • 原文地址:https://www.cnblogs.com/linzhengmin/p/11391922.html
Copyright © 2011-2022 走看看