洛谷 P5853 - [USACO19DEC]Tree Depth P(生成函数+背包)
神仙题。
首先考虑一个点的深度是什么,注意到对于笛卡尔树而言直接从序列的角度计算一个点的深度是不容易的,因为这样会牵扯到序列中多个元素,需要 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(生成函数+背包)的更多相关文章
- 【题解】洛谷P1273 有线电视网(树上分组背包)
次元传送门:洛谷P1273 思路 一开始想的是普通树形DP 但是好像实现不大好 观摩了一下题解 是树上分组背包 设f[i][j]为以i为根的子树中取j个客户得到的总价值 我们可以以i为根有j组 在每一 ...
- 【洛谷】P1541 乌龟棋(四维背包dp)
题目背景 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 题目描述 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起 ...
- 【题解】洛谷P1941 [NOIP2014TG] 飞扬的小鸟(背包DP)
次元传送门:洛谷P1941 思路 从题意可知 在每个单位时间内 可以无限地向上飞 但是只能向下掉一次 所以我们可以考虑运用背包解决这道题 上升时 用完全背包 下降时 用01背包 设f[x][y]为在坐 ...
- 【题解】洛谷P1541 [NOIP2010TG] 乌龟棋(类似背包的DP)
题目来源:洛谷P1541 思路 类似背包的题 总之就是四种卡牌取的先后顺序不同导致的最终ans不同 所以我们用一个四维数组每一维分别表示第几种取了几张的最大分数 然后就是简单DP解决 代码 #incl ...
- 洛谷P5206 [WC2019] 数树(生成函数+容斥+矩阵树)
题面 传送门 前置芝士 矩阵树,基本容斥原理,生成函数,多项式\(\exp\) 题解 我也想哭了--orz rqy,orz shadowice 我们设\(T1,T2\)为两棵树,并定义一个权值函数\( ...
- [USACO19DEC]Tree Depth P
题意 求逆序对为\(k\)的\(n\)排列中,生成的笛卡尔数,每个位置的深度和.\(n\le 300\) 做法 设\(f_{k}\)为\(n\)排列中逆序对为\(k\)的个数,其生成函数为:\[\pr ...
- 【洛谷P4178】Tree
题面 题解 感觉和\(CDQ\)分治一样套路啊 首先,构建出点分树 对于每一层分治重心,求出它到子树中任意点的距离 然后\(two-pointers\)计算满足小于等于\(K\)的点对数目,加入答案 ...
- BZOJ2654 & 洛谷2619:tree——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2654 https://www.luogu.org/problemnew/show/P2619 给你 ...
- 洛谷4178 BZOJ1468 Tree题解点分治
点分治的入门练习. 题目链接 BZOJ的链接(权限题) 关于点分治的思想我就不再重复了,这里重点说一下如何判重. 我们来看上图,假设我们去除了1节点,求出d[2]=1,d[3]=d[4]=2 假设k为 ...
随机推荐
- spring cloud config的使用
在传统的应用中,我们的配置文件都是放在项目中,这个影响不大.但是在一个微服务架构的系统中,我们的微服务可能存在几十上百个,并且每个小的微服务可能又部署在多台机器上,那么这个时候如果我们的配置文件在都放 ...
- 广域网(ppp协议、HDLC协议)
文章转自:https://blog.csdn.net/weixin_43914604/article/details/105028759 学习课程:<2019王道考研计算机网络> 学习目的 ...
- 21.10.9 test
T1 购票方案 \(\color{green}{100}\) 对于每个时间节点维护它作为每种票所能包含的最后一个点时,这种票的起始点位置,由于这个位置是单调的,所以类似双指针维护,\(O(KN)\) ...
- 2021NOI同步赛
\(NOI\) 网上同步赛 明白了身为菜鸡的自己和普通人的差距 DAY1 \(T1\) 轻重边 [题目描述] 小 W 有一棵 \(n\) 个结点的树,树上的每一条边可能是轻边或者重边.接下来你需要对树 ...
- Node.js躬行记(13)——MySQL归档
当前我们组管理着一套审核系统,除了数据源是服务端提供的,其余后台管理都是由我们组在维护. 这个系统就是将APP中的各类社交信息送到后台,然后有专门的审核人员来判断信息是否合规,当然在送到后台之前已经让 ...
- 链表中倒数第K个结点 牛客网 程序员面试金典 C++ Python
链表中倒数第K个结点 牛客网 程序员面试金典 C++ Python 题目描述 输入一个链表,输出该链表中倒数第k个结点. C++ /* struct ListNode { int val; struc ...
- 第k短路(Dijkstra & A*)
最短路,即第1短路有很多种求法,SPFA,Dijkstra等,但第k短路怎么求呢?其实也是基于Dijkstra:因为Dijkstra用的是堆优化,这样保证每次弹出来的都是最小值,只是求最短路只是弹出一 ...
- Can't open PID file /run/zabbix/zabbix_agentd.pid
神奇的事情,重启主机(reboot)后查看状态是正常的没有报错,重启zabbix-agent后,报无法打开zabbix_agentd.pid,zabbix-web正常监控 1.首先,/etc/zabb ...
- 测试平台系列(71) Python定时任务方案
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 定时任务 定时任务,顾名思义: ...
- ELK集群之kibana(4)
kibane安装及基础使用 Kibana的安装 Kibana包含前端展示.es操作简化 yum localinstall kibana-7.6.2-x86_64.rpm -y Kibana配置修改ki ...