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\n",dp[n][m]);
52 
53     return 0;
54 }
View Code

 

posted @ 2019-10-22 11:08  HHHyacinth  阅读(209)  评论(0编辑  收藏  举报