CodeForces - 1000D:Yet Another Problem On a Subsequence (DP+组合数)

博客详细解析了CodeForces中1000D问题,该问题涉及定义一个数列为“好的”标准,并要求计算“好的”子序列的数量。作者通过动态规划(DP)和组合数的方法来解决这个问题,指出关键在于理解dp[i]表示的意义,即以data[i]开头的“好”子序列的数量。转移方程为dp[i] = c[j - i - 1][a[i]] * dp[j],并解释了为何dp[n + 1]初始化为1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CodeForces - 1000D:Yet Another Problem On a Subsequence (DP+组合数)

题目大意:这题目啊,贼难理解…
定义一个数列是“好的”:第一个数字a[0]为数列长度+1。
定义一个数列的子序列是“好的”:这个子序列能分割成几个(包括一个)“好的”数列。
各一个数列,求“好的”子序列的数目。
题目分析:想了好久没想出来。主要是方向想错了,我想的是dp[i]表示1~i有多少个,但是这样跑到第i个的时候很难往前去处理怎么结合。看了别人的题解顿悟了。
dp[i]表示从i-n,由data[i]打头的good subsequence个数。很显然我们枚举good sequence可以接的位置是 j = i+a[i]+1 到 n,转移方程就是dp[i] = c[ j -i -1][ a[i] ] * dp[j] 【乘法原理】。
dp[n + 1] = 1,想了想为什么要这样设,因为当2 1 1求dp[1]时下一个要接的位置是4,但是已经没有了,这是2 1 1本身就是一个good subsequence,dp[4]就是1。

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

typedef long long ll;
const int maxn = 1e3 + 100;
const int mod = 998244353;

ll dp[maxn], data[maxn];
ll c[maxn][maxn];

int main()
{

   int n;
   scanf("%d", &n);
   for(int i = 0; i <= n; i++) {
      c[i][0] = c[i][i] = 1;
      c[i][1] = i;
   }

   for(int i = 1; i <= n; i++) {
      for(int j = 1; j <= n; j++) {
         c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
         //这里处理组合数,而不是用逆元 学到了
      }
   }

   for(int i = 1; i <= n; i++) {
       scanf("%lld", &data[i]);
   }

   dp[n + 1] = 1;
   for(int i = n; i > 0; i--) {
      if(data[i] <= 0) continue;
      for(int j = data[i] + i + 1; j <= n + 1; j++) {
          dp[i] = dp[i] + (c[j - i - 1][data[i]] * dp[j]) % mod;
          dp[i] %= mod;
      }

   }

   ll sum = 0;
   for(int i = 1; i <= n; i++)
    sum = (sum + dp[i]) % mod;

   printf("%lld\n", sum);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值