题目大意
- 定义一个数列是“好的”:第一个数字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;
}
原文地址:https://www.cnblogs.com/RFisher/p/9248648.html
时间: 2024-11-09 02:18:59