Yet Another Problem On a Subsequence(dp+组合数)

Yet Another Problem On a Subsequence

The sequence of integers a1,a2,…,ak is called a good array if a1=k−1 and a1>0. For example, the sequences [3,−1,44,0],[1,−99] are good arrays, and the sequences [3,7,8],[2,5,4,1],[0]

— are not.

A sequence of integers is called good if it can be divided into a positive number of good arrays. Each good array should be a subsegment of sequence and each element of the sequence should belong to exactly one array. For example, the sequences [2,−3,0,1,4]
, [1,2,3,−3,−9,4] are good, and the sequences [2,−3,0,1], [1,2,3,−3−9,4,1]

— are not.

For a given sequence of numbers, count the number of its subsequences that are good sequences, and print the number of such subsequences modulo 998244353.

Input

The first line contains the number n (1≤n≤103)

— the length of the initial sequence. The following line contains n integers a1,a2,…,an (−109≤ai≤109)

— the sequence itself.

Output

In the single line output one integer — the number of subsequences of the original sequence that are good sequences, taken modulo 998244353.

Examples
Input

3
2 1 1

Output

2

Input

4
1 1 1 1

Output

7

Note

In the first test case, two good subsequences — [a1,a2,a3]and [a2,a3]

.

In the second test case, seven good subsequences — [a1,a2,a3,a4],[a1,a2],[a1,a3],[a1,a4],[a2,a3],[a2,a4]and [a3,a4].

题意:

定义一个数列(good array)是“好的”:第一个数字a[0]为 数列长度+1。

定义一个数列的子序列(good sequence)是“好的”:这个子序列能分割成几个“好的”数列。(子序列可以不连续)

给一个长度为n的序列,求“好的”子序列(good sequence)的数目。

分析:

good sequence的本质就是多个good array相连,一个good array后面加good sequence还是good sequence。

所以我们可以利用组合数求出一个good array的个数然后后面接上good sequence,,而后面的good sequence同样也是由一个good array接后面一个good sequence

这样我们定义

d p [ i ] : 从i位置开始打头,good sequence的个数

我们从后往前遍历便可一步一步递推得到长度为n的数列的所有good sequence的种类数

那么递推式怎么写呢?


根据题意第一个打头的元素如果是 a [ i ] ,那么这样的一个good array的长度很明显根据题意应该是

a [ i ] + 1

那么后面接的good sequence应该从 j = i + a [ i ] + 1 位置开始

然后往后一直可以遍历到 n + 1

为什么可以到 n + 1 呢,当 j = n + 1 时,相当于后面不接good sequence,只有good array

这时我们考虑good array有多少种

首先 a [ i ] 是固定的必须得有,那么 j i 就是相当于可选长度,而因为 a [ i ] 固定必须有,所以 j i 1 为可选的长度。

因为good array的长度为 a [ i ] + 1 ,而我们已经固定了第一个数,那么我们还需要 a [ i ] 个数,所以实际上我们就是从中间 j i 1 个数中选择 a [ i ] 个数

即:

C j i 1 a [ i ]

这样我们得到了good array的个数,因为后面是接good sequence的个数,根据乘法原理,我们直接乘上以j开头的good sequence的个数即 d p [ j ] 即可

这样我们就得到了递推式

d p [ i ] = C j i 1 a [ i ] d p [ j ]

很明显根据这个式子我们应该从后往前推

这样总的结果把以每个位置为开头的good sequence个数再加起来就是答案

注意不存在以第n个位置为开头的,因为这样长度为1,第一个元素必须为0,而0是不满足题意的,这样我们倒着递推只需要从n-1到1即可


code:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int mod = 998244353;
int a[1005];
ll dp[1005],c[1005][1005];
int n;
int main(){
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        scanf("%d",&a[i]);
    }
    for(int i = 1; i <= 1000; i++){
        for(int j = 1; j <= 1000; j++){
            if(j == 1) c[i][j] = i;
            else c[i][j] = (c[i-1][j] + c[i-1][j-1]) % mod;
        }
    }//打表组合数

    dp[n+1] = 1;
    for(int i = n-1; i >= 1; i--){
        if(a[i] <= 0 || a[i] + i > n) continue;//小于等于0的不能为开头,good array超过了总长度不需要考虑
        for(int j = i + a[i] + 1; j <= n+1; j++){
            dp[i] += c[j-i-1][a[i]] * dp[j];
            dp[i] %= mod;
        }
    }
    int sum = 0;
    for(int i = 0; i < n; i++){
        sum += dp[i];
        sum %= mod;
    }
    printf("%d\n",sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/81323935