#dp# Codeforces D. Yet Another Problem On a Subsequence

本文介绍了一种通过动态规划解决特定子序列计数问题的方法,该问题要求计算满足特定条件的子序列数量,并通过组合数学进行状态转移。

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

题目链接

D. Yet Another Problem On a Subsequence

time limit per test  2 seconds

memory limit per test  256 megabytes

The sequence of integers a1,a2,…,aka1,a2,…,ak is called a good array if a1=k−1a1=k−1 and a1>0a1>0. For example, the sequences [3,−1,44,0],[1,−99][3,−1,44,0],[1,−99] are good arrays, and the sequences [3,7,8],[2,5,4,1],[0][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][2,−3,0,1,4], [1,2,3,−3,−9,4][1,2,3,−3,−9,4] are good, and the sequences [2,−3,0,1][2,−3,0,1], [1,2,3,−3−9,4,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)n (1≤n≤103) — the length of the initial sequence. The following line contains nn integers a1,a2,…,an (−109≤ai≤109)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][a1,a2,a3] and [a2,a3][a2,a3].

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

 

题目描述:

给出一个长度为n的序列,问子序列(可以不连续)中存在多少个good sequence。

good sequence 的规定如下:如果一个array的长度为k,且array的第一个元素array[1]为k-1(array[1] > 0),则称这个array为good array,由一个或多个array连接组成的sequence称为good sequence 。

 

Solution:

dp[i] 表示以 a[i] 为首元素的good sequence的个数,故dp[i] 可以由 dp[i+1] 转化而来。

首先枚举起点 i 的位置,即从 n-1 ~ 1 倒序枚举(由于array长度最少为2,所以从n-1开始),那么对于每个当前good array的起始元素为 i 位置,假定后面可以接的其它的good array的起始元素为 a[j],对于序列长度最少为 a[i] + 1了来说,那么 j 的起始位置就是 i + a[i] + 1,终止位置为 n + 1(j = n+1 时表示此时后面不再接其它的good array),可以得出,对于当前的array来说,他的组成元素是从 j - i - 1 个元素中任选 a[i] 个。对于可选的元素为j - i - 1 个解释:容易得出,在 j 位置与 i 位置之间,一共有 j - i + 1 个元素,由于元素 a[i] 本身已经确定为当前array的首元素,而 a[j] 也已经确定为是下一个array的首元素,所以 a[i] 和 a[j] 都不能选,所以需要从 j - i - 1 个元素中选取 a[i] 个。

可以得出转移方程为:

dp[i] = c[ j - i -1][a[i] ] * dp[j]。(组合数c[i][j] 表示从 j - i - 1 这些个元素中任取出a[i]个元素)

 

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#define mst(a, b) memset(a, b, sizeof(a))
#define rush() int T; cin >> T; while(T--)
using namespace std;
typedef long long LL;
const int MaxN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const LL Mod = 998244353;
const double eps = 1e-9;

LL a[1005], c[1005][1005];
LL dp[1005];
int n;

void init() {
    cin >> n;
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= n; j++) {
			if(j == 1) c[i][j] = i;
			else c[i][j] = (c[i-1][j] + c[i-1][j-1]) % Mod; //预处理组合数结果
		}
	}
    for(int i = 1; i <= n; i++) cin >> a[i];
}
int main() 
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);

	init();
	dp[n + 1] = 1LL; //当前array 后面不接其它的array
	LL sum = 0LL;
	for(int i = n - 1; i >= 1; i--) {
		if(a[i] <= 0) continue;
		for(int j = i + a[i] + 1; j <= n + 1; j++) {
			dp[i] += c[j-i-1][a[i]] * dp[j];
			dp[i] %= Mod;
		}
		sum = (sum + dp[i]) % Mod; //答案为每个i位置上可能的array数目之和
	}
	cout << sum << endl;
	return 0;
}

 

### Codeforces Div.2 比赛难度介绍 Codeforces Div.2 比赛主要面向的是具有基础编程技能到中级水平的选手。这类比赛通常吸引了大量来自全球不同背景的参赛者,包括大学生、高中生以及一些专业人士。 #### 参加资格 为了参加 Div.2 比赛,选手的评级应不超过 2099 分[^1]。这意味着该级别的竞赛适合那些已经掌握了一定算法知识并能熟练运用至少一种编程语言的人群参与挑战。 #### 题目设置 每场 Div.2 比赛一般会提供五至七道题目,在某些特殊情况下可能会更多或更少。这些题目按照预计解决难度递增排列: - **简单题(A, B 类型)**: 主要测试基本的数据结构操作和常见算法的应用能力;例如数组处理、字符串匹配等。 - **中等偏难题(C, D 类型)**: 开始涉及较为复杂的逻辑推理能力和特定领域内的高级技巧;比如图论中的最短路径计算或是动态规划入门应用实例。 - **高难度题(E及以上类型)**: 对于这些问题,则更加侧重考察深入理解复杂概念的能力,并能够灵活组合多种方法来解决问题;这往往需要较强的创造力与丰富的实践经验支持。 对于新手来说,建议先专注于理解和练习前几类较容易的问题,随着经验积累和技术提升再逐步尝试更高层次的任务。 ```cpp // 示例代码展示如何判断一个数是否为偶数 #include <iostream> using namespace std; bool is_even(int num){ return num % 2 == 0; } int main(){ int number = 4; // 测试数据 if(is_even(number)){ cout << "The given number is even."; }else{ cout << "The given number is odd."; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值