D. Yet Another Problem On a Subsequence[排列组合dp]

D. Yet Another Problem On a Subsequence
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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
inputCopy
3
2 1 1
outputCopy
2
inputCopy
4
1 1 1 1
outputCopy
7

我们用dp[i]dp[i]表示以第ii位开始的good sequences的数目。
首先使dp[n+1]=1,因为最后一位不选也是一种方案,有利于之后dp的转移。
我们发现两个good sequence首尾相连还是一个good sequence。
所以利用这一个性质,枚举j从i+a[i]+1到n+1。由于是求子序列的数目,所以只需在j−i−1个数字当中任选a[i]个就可以了。组合数的结果乘上dp[i]就可以了。

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define MP make_pair
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,ll>pll;
typedef vector<int> VI;
const int MX=1000+5;
const int mod=998244353;
 
int n;
int a[MX];
ll dp[MX],res[MX];
ll C[MX][MX];
void init(){
	C[0][0] = 1;
	for(int i = 1;i < MX;i++){
		C[i][0] = C[i][i] = 1;
		for(int j = 1;j < i;j++){
			C[i][j] = (C[i-1][j-1] + C[i-1][j])%mod;
		}
	}
}
 
int main(){
	init();
	scanf("%d",&n);
	for(int i=1;i<=n;i++) 
		scanf("%d",&a[i]);
	for(int i=n;i>=1;i--){
		if(a[i]>0 && a[i]+i<=n){
			for(int j=a[i]+i;j<=n;j++){
				dp[i]=(dp[i]+(C[j-i-1][a[i]-1]*(1+res[j+1])%mod))%mod;
			}
		}
		res[i]=(res[i+1]+dp[i])%mod;
	}
	printf("%lld\n",res[1]%mod);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值