Educational Codeforces Round 46 D. Yet Another Problem On a Subsequence

时间:2020-11-27 21:13:43

题目大意

  • 定义一个数列是“好的”:第一个数字a[0]为数列长度+1。
  • 定义一个数列的子序列是“好的”:这个子序列能分割成几个“好的”数列。
  • 各一个数列,求“好的”子序列的数目。

解题思路

  • 一开始想用dp[i][j]表示[i,j]的“好的”子序列的数目。发现复杂度爆炸,而且会造成重复。
  • 为了减少复杂度,避免重复。dp[i]表示后缀i,以a[i]为起始的“好的”子序列的数目。由于一个“好的”子序列能被分割。于是dp方程为:\(dp_i = \sum\limits_{j = i + a_i + 1}^{n + 1} {C_{j - i - 1}^{a_i} \cdot dp_j}\)
  • 最后答案为\(\sum\limits_{i=1}^{n}{dp_i}\)

代码

#include <bits/stdc++.h>
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define DEP(i,a,b) for(int i=(a); i>=(b); i--)
#define N 1010
using namespace std;
typedef long long LL;
const LL mod = 998244353;

int n;
LL a[N], dp[N];
LL C[N][N];

int main()
{
    scanf("%d", &n);
    C[0][0] = 1;
    REP(i, 1, n+1) {
        C[i][0] = C[i][i] = 1;
        REP(j, 1, i)
                C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
    }
    REP(i, 1, n+1) scanf("%lld", &a[i]);
    memset(dp, 0, sizeof(dp));
    dp[n+1] = 1;
    DEP(i, n, 1) {
        if (a[i] <= 0) {dp[i] = 0; continue;}
        REP(j, i+a[i]+1, n+2)
                dp[i] = (dp[i] + (C[j-i-1][a[i]] * dp[j] % mod)) % mod;
    }
    LL res = 0;
    REP(i, 1, n+1) res = (res + dp[i]) % mod;
    printf("%lld\n", res);
    return 0;
}