[CF1000D] Yet Another Problem On a Subsequence - 组合,dp

时间:2021-03-05 13:10:49   收藏:0   阅读:0

[CF1000D] Yet Another Problem On a Subsequence - 组合,dp

Description

如果一个数组\([a_1,a_2,a_3,...,a_n]a_1=n-1\)并且\(a1>0\),这个数组就被叫为好数组,如果一个序列能正好分为多个好数组,ta就被叫为好序列,现在给定一个序列,求这个序列有多少好子序列,答案对\(998244353\)取模

Solution

\(f[i]\) 表示从 i 开始选取,有多少个符合条件的序列

转移时候需要倒着来,从后往前转移

每次枚举本次选取的是哪些元素即可

注意小于等于 0 的那些不能选,要丢掉

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int mod = 998244353;

namespace math_mod
{
    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
    }

    int inv(int p)
    {
        return qpow(p, mod - 2);
    }

    int fac(int p)
    {
        if (p == 0)
            return 1;
        return p * fac(p - 1) % mod;
    }

    int ncr(int n, int r)
    {
        if (r < 0 || r > n)
            return 0;
        return fac(n) * inv(fac(r)) % mod * inv(fac(n - r)) % mod;
    }

    int c__[5005][5005];

    void c_presolve()
    {
        for (int i = 0; i <= 5000; i++)
        {
            c__[i][0] = c__[i][i] = 1;
            for (int j = 1; j < i; j++)
                c__[i][j] = c__[i - 1][j] + c__[i - 1][j - 1], c__[i][j] %= mod;
        }
    }

    int __c(int n, int r)
    {
        if (r < 0 || r > n)
            return 0;
        if (n > 5000)
            return ncr(n, r);
        return c__[n][r];
    }
}

using namespace math_mod;

int f[5005], a[5005];

signed main()
{
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    c_presolve();

    f[n + 1] = 1;
    for (int i = n; i >= 1; i--)
    {
        if (a[i] <= 0)
            continue;
        for (int j = i + a[i] + 1; j <= n + 1; j++)
        {
            f[i] += f[j] * __c(j - i - 1, a[i]);
            f[i] %= mod;
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; i++)
        ans += f[i];
    cout << ans % mod << endl;
}
评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!