洛谷题面传送门

神仙题。

首先考虑一个点的深度是什么,注意到对于笛卡尔树而言直接从序列的角度计算一个点的深度是不容易的,因为这样会牵扯到序列中多个元素,需要 fixed 的东西太多,计算起来太复杂了。因此考虑从树本身的角度计算一个点的深度。注意到对于一棵树上所有点 \(u\)​ 而言都有 \(dep_u=\sum\limits_{v}[\text{LCA}(u,v)=v]\)​,因此我们求解一个点 \(x\)​ 的答案时,可以枚举所有 \(u,v\)​ 并计算 \(v\)​ 对 \(u\)​ 的贡献,即,有多少个排列满足逆序对个数为 \(k\)​,且笛卡尔树上 \(v\)​ 为 \(u\)​​ 的祖先。并且我们还可以注意到,对于一个序列而言,其笛卡尔树上某两点存在祖先关系是存在充要条件转化的,具体来说,\(\text{LCA}(u,v)=v\) 当且仅当 \(a_v\) 为 \(a[\min(u,v)…\max(u,v)]\) 的最小值,因此我们只需求解以下问题:

有多少个排列 \(p\),满足其逆序对个数为 \(k\),且 \(a_v=\min\limits_{i=\min(u,v)}^{\max(u,v)}a_i\)

这个问题看似难以下手,因为外面就已经枚举了两维 \(u,v\) 了,里面这东西也无法直接组合数求解,需要用 DP 之类的东西,一弄最低就是 \(n^3\),直接爆炸,不过细想其实不用复杂度那么高。我们首先考虑如果没有第二个条件怎么求,我们设 \(dp_{i,j}\) 表示有多少个长度为 \(i\) 的排列有 \(j\) 个逆序对,考虑怎么转移,不难发现,对于长度为 \(i+1\) 的排列,我们总能找到唯一的 \(a_{i+1}\),满足 \(a_{i+1}\) 与前面 \(i\) 个数产生的逆序对数为 \(x(x\in[0,i])\),也就是说 \(dp_{i+1,j}=\sum\limits_{x=0}^idp_{i,j-x}\),前缀和优化一下即可,这个在 CF1542E2 Abnormal Permutation Pairs (hard version) 中就已经见过了。对于此题亦是如此,与经典问题不同的一点是,直接按照 \(1,2,3,\cdots,n\) 的位置填数会爆炸,因此考虑换个顺序,如果 \(u<v\) 那么我们就按照 \(u,u+1,u+2,\cdots,v,u-1,u-2,\cdots,1,v+1,v+2,\cdots,n\) 的顺序填数,否则我们按照 \(u,u-1,u-2,\cdots,v,u+1,u+2,\cdots,n,v-1,v-2,\cdots,1\) 的顺序填。不难发现按照这样的顺序填数之后,其他位置上的填法都和前面一样,即第 \(i\) 个填的数可以为排列逆序对数产生 \([0,i-1]\) 中任意一个数的贡献,唯独 \(v\) 只有一种填法。而两种情况的差别的,前一种情况 \(v\) 会对排列逆序对数产生 \(|u-v|\) 的贡献,而后一种不会,因此如果写成生成函数的形式,就是前一种情况的方案数为 \([x^k]·x^{|u-v|}\prod\limits_{i=0}^{|u-v|-1}(\sum\limits_{j=0}^ix^j)·\prod\limits_{i=|u-v|+1}^{n-1}(\sum\limits_{j=0}^ix^j)\),后一种情况的方案数为 \(x^{|u-v|}\prod\limits_{i=0}^{|u-v|-1}(\sum\limits_{j=0}^ix^j)·\prod\limits_{i=|u-v|+1}^{n-1}(\sum\limits_{j=0}^ix^j)\),注意到对于一对 \(u,v\) 而言,上面两个式子的值只与 \(|u-v|\) 有关,因此可以对所有 \(|u-v|\) 预处理一波答案,复杂度 \(\mathcal O(n^4)\)。如果你观察能力再强一些,你还能发现这式子可以写成背包的形式,你对前后缀各做一遍背包就可以 \(n^3\) 求解了。

const int MAXN=300;
const int MAXK=44850;
int n,k,mod;
int pre[MAXN+5][MAXK+5],suf[MAXN+5][MAXK+5];
int sum[MAXK+5],c1[MAXN+5],c2[MAXN+5];
int getsum(int l,int r){return (sum[r]-((!l)?0:sum[l-1])+mod)%mod;}
int main(){
scanf("%d%d%d",&n,&k,&mod);pre[0][0]=1;
for(int i=0;i<=k;i++) sum[i]=1;
for(int i=1;i<n;i++){
for(int j=0;j<=k;j++) pre[i][j]=getsum(j-i,j);
memset(sum,0,sizeof(sum));sum[0]=pre[i][0];
for(int j=1;j<=k;j++) sum[j]=(sum[j-1]+pre[i][j])%mod;
} suf[n][0]=1;
for(int i=0;i<=k;i++) sum[i]=1;
for(int i=n-1;~i;i--){
for(int j=0;j<=k;j++) suf[i][j]=getsum(j-i,j);
memset(sum,0,sizeof(sum));sum[0]=suf[i][0];
for(int j=1;j<=k;j++) sum[j]=(sum[j-1]+suf[i][j])%mod;
} c1[0]=c2[0]=pre[n-1][k];
for(int i=1;i<n;i++){
for(int j=0;j<=k;j++) c1[i]=(c1[i]+1ll*pre[i-1][j]*suf[i+1][k-j])%mod;
for(int j=0;j<=k-i;j++) c2[i]=(c2[i]+1ll*pre[i-1][j]*suf[i+1][k-i-j])%mod;
} for(int i=1;i<=n;i++){
int res=0;
for(int j=1;j<=n;j++){
if(j<=i) res=(res+c1[i-j])%mod;
else res=(res+c2[j-i])%mod;
} printf("%d%c",res," \n"[i==n]);
}
return 0;
}

洛谷 P5853 - [USACO19DEC]Tree Depth P(生成函数+背包)的更多相关文章

  1. 【题解】洛谷P1273 有线电视网(树上分组背包)

    次元传送门:洛谷P1273 思路 一开始想的是普通树形DP 但是好像实现不大好 观摩了一下题解 是树上分组背包 设f[i][j]为以i为根的子树中取j个客户得到的总价值 我们可以以i为根有j组 在每一 ...

  2. 【洛谷】P1541 乌龟棋(四维背包dp)

    题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起 ...

  3. 【题解】洛谷P1941 [NOIP2014TG] 飞扬的小鸟(背包DP)

    次元传送门:洛谷P1941 思路 从题意可知 在每个单位时间内 可以无限地向上飞 但是只能向下掉一次 所以我们可以考虑运用背包解决这道题 上升时 用完全背包 下降时 用01背包 设f[x][y]为在坐 ...

  4. 【题解】洛谷P1541 [NOIP2010TG] 乌龟棋(类似背包的DP)

    题目来源:洛谷P1541 思路 类似背包的题 总之就是四种卡牌取的先后顺序不同导致的最终ans不同 所以我们用一个四维数组每一维分别表示第几种取了几张的最大分数 然后就是简单DP解决 代码 #incl ...

  5. 洛谷P5206 [WC2019] 数树(生成函数+容斥+矩阵树)

    题面 传送门 前置芝士 矩阵树,基本容斥原理,生成函数,多项式\(\exp\) 题解 我也想哭了--orz rqy,orz shadowice 我们设\(T1,T2\)为两棵树,并定义一个权值函数\( ...

  6. [USACO19DEC]Tree Depth P

    题意 求逆序对为\(k\)的\(n\)排列中,生成的笛卡尔数,每个位置的深度和.\(n\le 300\) 做法 设\(f_{k}\)为\(n\)排列中逆序对为\(k\)的个数,其生成函数为:\[\pr ...

  7. 【洛谷P4178】Tree

    题面 题解 感觉和\(CDQ\)分治一样套路啊 首先,构建出点分树 对于每一层分治重心,求出它到子树中任意点的距离 然后\(two-pointers\)计算满足小于等于\(K\)的点对数目,加入答案 ...

  8. BZOJ2654 & 洛谷2619:tree——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=2654 https://www.luogu.org/problemnew/show/P2619 给你 ...

  9. 洛谷4178 BZOJ1468 Tree题解点分治

    点分治的入门练习. 题目链接 BZOJ的链接(权限题) 关于点分治的思想我就不再重复了,这里重点说一下如何判重. 我们来看上图,假设我们去除了1节点,求出d[2]=1,d[3]=d[4]=2 假设k为 ...

随机推荐

  1. CentOS 用户与群组

    目录 1.用户管理 1.1.切换用户 1.2.添加用户 1.3.删除用户 1.4.修改用户 2.群组管理 2.1.查看群组 2.2.添加群组 2.3.删除群组 2.4.修改群组 1.用户管理 Linu ...

  2. 关于takin-data,你想知道的都在这里(一)启动命令篇

    通过docker部署体验takin的小伙伴都应该知道,在安装部署手册中有提到:在启动surge-deploy任务前,需要将启动命令中的ip参数替换为docker容器所在宿主机的ip,很多小伙伴都在这里 ...

  3. Java:HashTable类小记

    Java:HashTable类小记 对 Java 中的 HashTable类,做一个微不足道的小小小小记 概述 public class Hashtable<K,V> extends Di ...

  4. JVM:类加载与字节码技术-2

    JVM:类加载与字节码技术-2 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 内容 这部分内容在上一篇笔记中: 类文件结构 字节码指令 编译期处理 类加载阶段 ...

  5. Beta阶段初始任务分配

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 团队项目-计划-Beta阶段说明书 一.Beta阶段总体规划 根据用户反馈与测试结果修复alpha版本的bu ...

  6. CentOS系统优化一键配置脚本

    #!/usr/bin/env bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export P ...

  7. 零基础入门非常好的C语言基础资料

    C语言程序的结构认识 用一个简单的c程序例子,介绍c语言的基本构成.格式.以及良好的书写风格,使小伙伴对c语言有个初步认识. 例1:计算两个整数之和的c程序: #include main() { in ...

  8. 【代码更新】单细胞分析实录(20): 将多个样本的CNV定位到染色体臂,并画热图

    之前写过三篇和CNV相关的帖子,如果你做肿瘤单细胞转录组,大概率看过: 单细胞分析实录(11): inferCNV的基本用法 单细胞分析实录(12): 如何推断肿瘤细胞 单细胞分析实录(13): in ...

  9. Python ValueError: Attempted relative import in non-package Relative import相对引用 错误

    包含相对路径import的python脚本不能直接运行,只能作为module被引用. 例如 from . import mod1 有这样代码的文件只能最为moulule为不能直接运行.相对路径就是相对 ...

  10. PWN环境搭建

    目录 PWN环境搭建 需要的工具或系统 安装PWN工具 pwntools (CTF库.漏洞利用库) pwngdb(GDB插件) checksec(查保护) ROPGadget(二进制文件查找工具) o ...