题目传送门

典型的 Atcoder 风格的计数 dp。

题目可以转化为每次在序列中插入一个 \([1,k]\) 的数,共操作 \(n\) 次,满足后一个序列的字典序严格大于前一个序列,问有多少种操作序列。

显然相同的数可以合并,因为在由相同的数 \(x\) 组成的数段中,在任何位置插入 \(x\),得到的序列都是相同的。

再考虑字典序的问题。你只能序列末尾或者一个 \(<x\) 的数前面插入 \(x\),否则得到的序列的字典序就会 \(\geq\) 原序列的字典序。

但这样问题还是比较棘手,我们还需进一步转化。

我们把操作序列转化为一棵有根树,树上每个节点都是一个二元组 \((val,dfn)\),表示第 \(dfn\) 次操作插入了值为 \(val\) 的数。如果第 \(i\) 次操作将 \(v\) 插在第 \(j\) 次操作插入的数 \(w\) 前面,那么我们就将节点 \((v,i)\) 挂在 \((w,j)\) 下面。新建一个虚拟节点 \((0,0)\),如果在序列末尾插入 \(v\),那么就把 \((v,i)\) 挂在 \((0,0)\) 下面。

由于我们只能在 \(<x\) 的数前面插入 \(x\),因此若 \(y\) 为 \(x\) 的父亲,那么 \(val_y>val_x\),\(dfn_y<dfn_x\)

不妨举个例子,假设有如下的操作序列:

  1. 向序列中插入数 \(1\),得到序列 \([1]\)。这可看成将点 \((1,1)\) 挂在点 \((0,0)\) 下面。
  2. 在 \(1\) 前插入 \(3\),得到序列 \([3,1]\)。这可看成将点 \((3,2)\) 挂在点 \((1,1)\) 下面。
  3. 在序列末尾插入 \(2\),得到序列 \([3,1,2]\)。这可看成将点 \((2,3)\) 挂在点 \((0,0)\) 下面。
  4. 在 \(1\) 再插入一个 \(3\),得到序列 \([3,3,1,2]\)。这可看成将点 \((3,4)\) 挂在点 \((1,1)\) 下面。
  5. 在 \(1\) 前插入一个 \(2\),得到序列 \([3,3,2,1,2]\)。这可看成将点 \((2,5)\) 挂在点 \((1,1)\) 下面。
  6. 在第二个 \(3\) 前插入一个 \(4\),得到序列 \([3,4,3,2,1,2]\)。这可看成将点 \((4,6)\) 挂在点 \((3,4)\) 下面。

这样 \(6\) 次操作下来,我们得到了一棵 \(7\) 个节点的树,如下图:



一种操作序列恰对应一棵树,一棵满足条件的树也对应一种操作序列。因此问题转化为有多少个满足条件的树。

这就可以直接 \(dp\) 了。我们设 \(dp_{i,j}\) 表示有多少个以 \(i\) 为节点的树,根节点的 \(val\) 为 \(j\)。

考虑转移,对于 \(i>1\),假设根节点的 \(dfn\) 为 \(1\),那么根节点必定有个儿子,其 \(dfn\) 为 \(2\)。我们就枚举这棵子树的大小 \(l\) 和根节点的 \(val\) —— \(v\)。确定这棵子树的形态的方案数为 \(dp_{l,v}\),将这棵子树中所有节点的 \(dfn\) 值定好的方案数为 \(C_{n-2}^{k-1}\)(从 \(3\) 到 \(n\) 这 \(n-2\) 个数中中选择 \(k-1\) 个数),填好剩余部分的方案数为 \(dp_{i-l,j}\)。因此有转移方程:

\[dp_{i,j}=\sum\limits_{l-1}^{i-1}C_{n-2}^{k-1} \times dp_{i-l,j} \times \sum\limits_{v=j+1}^k dp_{l,v}
\]

后面那个 \(\sum\) 可以用前缀和优化掉。时间复杂度 \(\mathcal O(n^2k)\)

/*
Contest: -
Problem: Atcoder Grand Contest 024 E
Author: tzc_wk
Time: 2020.7.22
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
#define int long long
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
int n=read(),k=read(),m=read();
int C[305][305],s[305][305],dp[305][305];
signed main(){
fz(i,0,300){
C[i][0]=1;
fz(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%m;
}
// printf("%d\n",C[5][3]);
fz(i,0,k) dp[1][i]=1;
fd(i,k,0) s[1][i]=(s[1][i+1]+dp[1][i])%m;
fz(i,2,n+1){
fz(j,0,k)
fz(l,1,i-1)
dp[i][j]=(dp[i][j]+C[i-2][l-1]*dp[i-l][j]%m*s[l][j+1]%m)%m;
fd(j,k,0) s[i][j]=(s[i][j+1]+dp[i][j])%m;
}
printf("%lld\n",dp[n+1][0]);
return 0;
}

Atcoder Grand Contest 024 E - Sequence Growing Hard(dp+思维)的更多相关文章

  1. AtCoder Grand Contest 019 B - Reverse and Compare【思维】

    AtCoder Grand Contest 019 B - Reverse and Compare 题意:给定字符串,可以选定任意i.j且i<=j(当然i==j时没啥卵用),然后翻转i到j的字符 ...

  2. [AtCoder Grand Contest 024 Problem E]Sequence Growing Hard

    题目大意:考虑 N +1 个数组 {A0,A1,…,AN}.其中 Ai 的长度是 i,Ai 内的所有数字都在 1 到 K 之间. Ai−1 是 Ai 的子序列,即 Ai 删一个数字可以得到 Ai−1. ...

  3. Atcoder Grand Contest 024

    A 略 B 略 C 略 D(构造分形) 题意: 给出一个由n个点的组成的树,你可以加一些点形成一个更大的树.对于新树中的两个点i和j,如果以i为根的树与以j为根的树是同构的那么i和j颜色可以相同.问最 ...

  4. Atcoder Grand Contest 005 E - Sugigma: The Showdown(思维题)

    洛谷题面传送门 & Atcoder 题面传送门 记先手移动棋子的树为红树,后手移动棋子的树为蓝树. 首先考虑一个性质,就是如果与当前红色棋子所在的点相连的边中存在一条边,满足这条边的两个端点在 ...

  5. Atcoder Grand Contest 022 E - Median Replace(dp)

    Atcoder 题面传送门 & 洛谷题面传送门 首先考虑对于固定的 01 串怎样计算它是否可以通过将三个连续的 \(0\) 或 \(1\) 替换为其中位数得到.我们考虑单调栈,新建一个栈,栈底 ...

  6. Atcoder Grand Contest 002 F - Leftmost Ball(dp)

    Atcoder 题面传送门 & 洛谷题面传送门 这道 Cu 的 AGC F 竟然被我自己想出来了!!!((( 首先考虑什么样的序列会被统计入答案.稍微手玩几组数据即可发现,一个颜色序列 \(c ...

  7. Atcoder Grand Contest 039C(容斥原理,计数DP)

    //每次操作相当于将最低位取反加到最高位(N~1位)#define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace s ...

  8. Atcoder Grand Contest 037C(贪心,优先队列,思维)

    #define HAVE_STRUCT_TIMESPEC//编译器中time.h和phread.h头文件中timespec结构体重名,故加此行#include<bits/stdc++.h> ...

  9. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

随机推荐

  1. Go语言核心36讲(Go语言进阶技术三)--学习笔记

    09 | 字典的操作和约束 至今为止,我们讲过的集合类的高级数据类型都属于针对单一元素的容器. 它们或用连续存储,或用互存指针的方式收纳元素,这里的每个元素都代表了一个从属某一类型的独立值. 我们今天 ...

  2. Python实现可视化操作

    # Author kevin_hou #简单的GUI文本编辑器 from tkinter import * from tkinter.scrolledtext import ScrolledText ...

  3. 错误 Unresolved reference 'AF_INET' 解决办法

    错误代码如下: import socketserer_socket = socket.socket(AF_INET, SOCK_DGAM) 错误信息: 原因分析: 1.AF_INET,SOCK_DGA ...

  4. AIApe问答机器人Scrum Meeting 4.25

    Scrum Meeting 2 日期:2021年4月25日 会议主要内容概述:前后端针对WebAPI进行协调与统一工作,商量接下来两日计划:敲定部分设计细节. 一.进度情况 组员 负责 两日内已完成的 ...

  5. BUAA2020软工作业(五)——软件案例分析

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件案例分析作业 我在这个课程的目标是 进一步提高自己的编码能力,工程能力 这个作业在哪个具体方面 ...

  6. 2021.9.26考试总结[NOIP模拟62]

    T1 set 从\(0\)到\(n\)前缀余数有\(n+1\)个,但只有\(n\)种取值,找到一样的两个输出区间即可. \(code:\) T1 #include<bits/stdc++.h&g ...

  7. stm32电机控制之控制两路直流电机

    小车使用的电机是12v供电的直流电机,带编码器反馈,这样就可以采用闭环速度控制,这里电机使用PWM驱动,速度控制框图如下: 由以上框图可知,STM32通过定时器模块输出PWM波来控制两个直流电机的转动 ...

  8. springboot使用之请求参数与基本注解

    @PathVariable 作用:@PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值,将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariabl ...

  9. CentOS7 hadoop3.3.1安装(单机分布式、伪分布式、分布式)

    @ 目录 前言 预先设置 修改主机名 关闭防火墙 创建hadoop用户 SSH安装免密登陆 单机免密登陆--linux配置ssh免密登录 linux环境配置Java变量 配置Java环境变量 安装Ha ...

  10. Python基础(序列化)

    #pickling import pickle,json # d = dict(name='傻狗1',age=300,score=100) # d1 = pickle.dumps(d)#pickle. ...