• CodeForces 1204E"Natasha, Sasha and the Prefix Sums"(动态规划 or 组合数学--卡特兰数的应用)


    传送门

    •参考资料

      [1]:CF1204E Natasha, Sasha and the Prefix Sums(动态规划+组合数)

    •题意

      由 n 个 和 个 -1 组成的 $C_{n+m}^{n}$ 个序列;

      对所有序列的最大前缀和求和;

      并规定最大前缀和最小是 0;

    •题解

      定义 $(i,j)$ 表示序列由 i 个 1,j 个 -1 组成;

      $(i,j)$ 共有 $C_{i+j}^{i}$ 种不同的组合方式;

      $(i-1,j)$ 共有 $C_{i+j-1}^{i-1}$ 种不同的组合方式;

      $(i,j-1)$ 共有 $C_{i+j-1}^{i}$ 种不同的组合方式;

      如果同时在 $(i-1,j)$ 的 $C_{i+j-1}^{i-1}$ 和 $(i,j-1)$ 的 $C_{i+j-1}^{i}$ 种组合方式的末尾或开头分别插入 1 或 -1;

      那便是 $(i,j)$ 的不同的组合方式的种类数,即 $C_{i+j}^{i}=C_{i+j-1}^{i-1}+C_{i+j-1}^{i}$;

      根据 n,m 的范围($leq 2000$),考虑用 DP 解决这道题目;

      首先,定义 $dp[i][j]$ 表示由 $(i,j)$ 组成的 $C_{i+j}^{i}$ 个序列,对所有序列的最大前缀和求和后的结果;

      有上述前置知识,很容易想到 $(i,j)$ 可由 $(i-1,j)$ 和 $(i,j-1)$ 得到;

      这也就是说,$dp[i][j]$ 可由 $dp[i-1][j]$ 和 $dp[i][j-1]$ 转移过来;

      因为 $(i,j)$ 可由 $(i-1,j)$ 和 $(i,j-1)$ 的末尾或开头插入 1 或 -1 得到,那到底是在开头插入还是结尾插入呢?

      因为题意让求的是前缀最大值之和,所以,我们考虑到在开头插入 1 或 -1:

      • 在 $(i-1,j)$ 的开头插入 1,也就意味着这 $C_{i+j-1}^{i-1}$ 个序列的前缀最大值都会增加 1,那么
        • $dp[i][j] += dp[i-1][j]+C_{i+j-1}^{i-1}$
      • 在 $(i,j-1)$ 的开头插入 -1,意味着这 $C_{i+j-1}^{i}$ 个序列的前缀最大值会减少 1,那么
        • $dp[i][j] += dp[i][j-1]-C_{i+j-1}^{i}+h[i][j-1]$

      

      $h[i][j-1]$ 是干啥用的呢?

      由题意,前缀最大值最小为 0,所以,在 $(i,j-1)$ 的开头插入 -1 的时候,前缀最大值为 0 的序列是不会减少 1 的;

      我们就需要将这些多减掉的 1 在加上;

      定义 $h[i][j]$ 表示 $(i,j)$ 的 $C_{i+j}^{i}$ 个序列种前缀最大值为 0 的个数;

      同样 $h[i][j]$ 可由 $h[i-1][j]$ 和 $h[i][j-1]$ 转移过来;

      考虑到 $h[i][j]$ 的定义,我们这次选择在 $(i-1,j)$ 和 $(i,j-1)$ 的结尾插入 1 或 -1;

      很容易想到,如果 $i > j$,一定有 $h[i][j]=0$,所以,我们考虑 $i le j$ 的情况;

      因为是在结尾插入的,所以,前缀最大值第一次出现的位置是不会改变的,所以有 $h[i][j]=h[i-1][j]+h[i][j-1]$;

    •Code

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define mem(a,b) memset(a,b,sizeof(a))
     5 const int maxn=2e3+50;
     6 const int MOD=998244853;
     7 
     8 int n,m;
     9 ll dp[maxn][maxn];
    10 ll h[maxn][maxn];
    11 ll C[2*maxn][2*maxn];
    12 
    13 void Init()
    14 {
    15     C[0][0]=1;
    16     for(int i=1;i < 2*maxn;++i)
    17         for(int j=0;j <= i;++j)
    18         {
    19             if(j == 0 || j == i)
    20                 C[i][j]=1;
    21             else
    22                 C[i][j]=C[i-1][j]+C[i-1][j-1];
    23             C[i][j] %= MOD;
    24         }
    25         
    26     mem(h,0);
    27     for(int j=0;j < maxn;++j)
    28         h[0][j]=1;
    29     for(int i=1;i < maxn;++i)
    30         for(int j=i;j < maxn;++j)
    31             h[i][j]=(h[i-1][j]+h[i][j-1])%MOD;
    32 
    33 
    34     dp[0][0]=0;
    35     for(int i=1;i < maxn;++i)
    36         dp[i][0]=i;
    37     for(int j=1;j < maxn;++j)
    38         dp[0][j]=0;
    39     for(int i=1;i < maxn;++i)
    40         for(int j=1;j < maxn;++j)
    41         {
    42             dp[i][j]=(dp[i-1][j]+C[i+j-1][j])+(dp[i][j-1]-C[i+j-1][i]+h[i][j-1]);
    43             dp[i][j]=(dp[i][j]+MOD)%MOD;
    44         }
    45 }
    46 
    47 int main()
    48 {
    49     Init();
    50     scanf("%d%d",&n,&m);
    51     printf("%lld
    ",dp[n][m]);
    52 
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    HDOJ 4747 Mex
    HDU 1203 I NEED A OFFER!
    HDU 2616 Kill the monster
    HDU 3496 Watch The Movie
    Codeforces 347A A. Difference Row
    Codeforces 347B B. Fixed Points
    Codeforces 372B B. Hungry Sequence
    HDU 1476 Sudoku Killer
    HDU 1987 How many ways
    HDU 2564 词组缩写
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/11718617.html
Copyright © 2020-2023  润新知