[CF1204E]Natasha,Sasha and the Prefix Sums 题解

时间:2019-08-21
本文章向大家介绍[CF1204E]Natasha,Sasha and the Prefix Sums 题解,主要包括[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(\begin{matrix} i \\ j\end{matrix}\right)\),那么:
\[f[i][j] = \left\{\begin{matrix} f[i-1][j]+1 \times C[i+j-1][i-1] \\ f[i][j-1]+(-1)\times(C[i+j-1][j-1]-k[i][j-1])\end{matrix}\right.\]
k[i][j]表示有i个1,j个-1的最大前缀和刚好为0的排列的个数
那么上式是如何推出的呢?
我们固定地认为每当新加入一个数的时候将该数插入序列的最前方,这种设定仍然保证了动规涵盖所有珂能的排列。
如果我们插入的是一个1,不管先前的序列排列如何,最大prefix sum一定会加1,由于i-1个1,j个-1对应的序列有\(\left(\begin{matrix} i+j-1 \\ i\end{matrix}\right)\)种排列方法,所以当前状态增加的贡献为\(\left(\begin{matrix} i+j-1 \\ i\end{matrix}\right)\)
如果我们插入的是一个-1,情况于上面是完全相同的,但是注意到,如果有一种排列它本身的"最大prefix sum"为0,那么我们不应当把它计入贡献(因为"最大prefix sum"最小为0),所以要减去k[i][j]。
组合数显然珂以通过杨辉三角递推解决。
那么现在我们的问题就在于k[i][j]如何处理。
我们先给出k[i][j]的递推式。
\[k[i][j]=\left\{\begin{matrix}i=0 & k[i][j]=1 \\ j=0 & k[i][j]=0 \\ i > j & k[i][j]=0 \\ \text{其余情况} & k[i][j]=k[i-1][j]+k[i][j-1]\end{matrix}\right.\]
这个递推式珂能有点晦涩,但是一种简单的理解方式是找出由当前状态向外转移的方程式,然后再转化为以上方程式。
于是我们解决了此题。

代码

没有卡常,见谅。

#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;
}

原文地址:https://www.cnblogs.com/linzhengmin/p/11391922.html