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

题目大意

  • 定义一个数列是“好的”:第一个数字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;
}

原文地址:https://www.cnblogs.com/RFisher/p/9248648.html

时间: 2024-11-09 02:18:59

Educational Codeforces Round 46 D. Yet Another Problem On a Subsequence的相关文章

Educational Codeforces Round 46 (Rated for Div. 2) D. Yet Another Problem On a Subsequence

这个题是dp, dp[i]代表以i开始的符合要求的字符串数 j是我们列举出的i之后一个字符串的开始地址,这里的C是组合数 dp[i] += C(j - i - 1, A[i]] )* dp[j]; #include <algorithm> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <map> #include &

Educational Codeforces Round 46 (Rated for Div. 2)E. We Need More Bosses

题目链接:E. We Need More Bosses 题解:tarjan有向图缩点之后求树的直径就是答案:应为在同一个强联通里的边就不是必须边,参考了这个 #include<bits/stdc++.h> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #includ

Educational Codeforces Round 46 C - Covered Points Count

C - Covered Points Count emmm 好像是先离散化一下 注意 R需要+1 这样可以确定端点 emmm 扫描线?瞎搞一下? #include<bits/stdc++.h> using namespace std; #define maxn 4000005 #define LL long long LL a[maxn],b[maxn],ll[maxn],rr[maxn],c[maxn]; LL x[maxn],y[maxn]; vector<LL >q; int

Educational Codeforces Round 46 (Rated for Div. 2) D

dp[i]表示一定包含第I个点的好的子序列个数,那么最终答案就是求dp[0] + dp[1] + .... + dp[n-1] 最终的子序列被分成了很多块,因此很明显我们枚举第一块,第一块和剩下的再去组合,然后我们为了保证没有重复,我们需要保证第一块不同,然而第一块的大小是固定的,因此我们可以选择枚举第一块最后一个数,这样第一块就肯定不会相同了,也可以计算 const ll P = 998244353; ll dp[maxn]; int N = 1000; ll comb[maxn][maxn]

Educational Codeforces Round 72 (Rated for Div. 2)-D. Coloring Edges-拓扑排序

Educational Codeforces Round 72 (Rated for Div. 2)-D. Coloring Edges-拓扑排序 [Problem Description] ? 给你一个有向图,给用最少的颜色给每条边染色,要保证不存在一个环中的所有边都是同一个颜色. [Solution] ? 用拓扑排序判断图中是否存在环,若图中不存在环,则所有边都是同一种颜色.否则,同一个环中,只要用两种颜色就可以满足题目条件,所以总的颜色数就是两种,对于一个环,一定会存在两种边:1.节点号小

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Educational Codeforces Round 22 E. Army Creation(主席树)

题目链接:Educational Codeforces Round 22 E. Army Creation 题意: 给你n个数和一个数k,然后有q个询问. 每个询问 有一个区间[l,r],问你这个区间内在满足每一种数不超过k的情况下,最大能选多少个数出来. 强制在线. 题解: 一看就要用到主席树,和主席数求区间内有多少不同的数的个数处理方法相同. 依次将每个数插入,当这个数出现的个数等于k了,就把最前面的那个数删掉. 然后询问就访问root[r]就行了. 第一次写完数据结构没有调试一遍过样例,一

Codeforces Round #400 D. The Door Problem(2-sat)

题目链接:Codeforces Round #400 D. The Door Problem 题意: 有n扇门,每扇门有个初始状态,并且受两个开关控制. 现在给你m个开关控制门的信息,每个开关能将它所控制的门的状态翻转. 问能不能通过一定操作,将所以的门的状态都处于开的情况. 题解: 这题用2sat,也可以用并查集判断联通块.这里我用2sat. 因为一个开关可以控制多扇门,而每个门只由两个开关控制,所以这里我们考虑对这m个开关建图. 如果这扇门的状态为1,那么要让它保持1的状态,我们只能同时按下