1. 程式人生 > >Educational Codeforces Round 46 D. Yet Another Problem On a Subsequence

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

mod ons ++ 數列 一個數 () -- problem dot

題目大意

  • 定義一個數列是“好的”:第一個數字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; }

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