当前位置: 首页 > news >正文

CF2122G Tree Parking 题解

题目链接

点击打开链接

题目解法

神题!
合法的条件是对于任意一对祖孙 \(x,y\),都需要满足 \([l_x,r_x]\)\([l_y,r_y]\) 包含,或者不交。
我们先考虑一棵给定的树如何计数 \((l,r)\) 的对数。
我们从下往上做,即考虑如何从 \(u\) 的儿子集合 \(son(u)\) 的答案推到点 \(u\) 的答案。
注意,我们这里考虑一个点 \(u\) 的答案时,是把 \(u\) 子树中 \(l,r\) 的集合当成 \(1\sim 2siz_u\) 的排列去做的。
首先 \(u\) 的儿子之间的 \(l,r\) 是可以任意合并的,然后考虑插入 \(l_u,r_u\)。根据上面的合法条件,不难得出 \(l_u=r_u-1\),即必须连续。
这样我们得出整棵树的方案数为 \(\prod\limits_{i=1}^n(2siz_i-1)\times (2siz_i-2)!\prod\limits_{j\in son(i)}\frac{1}{(2siz_j)!}\),整理可得 \(\frac{(2n)!}{2^n\prod\limits_{i=1}^n siz_i}\)
我们把这个式子变形成拓扑序计数的形式:\(\frac{(2n)!}{n!2^n}\times\) 树的拓扑序方案数,即我们只需要算出所有 \(n\) 个点有 \(k\) 个叶子的树的拓扑序方案数之和即可。
首先我们有一个递推式,令 \(f(n,k)\) 表示 \(n\) 个点 \(k\) 个叶子的拓扑序方案数。我们考虑添加一个叶子,这个点可以是非叶子节点的儿子,会增加叶子数;也可以是之前叶子节点的儿子,不会增加叶子数。
所以可得 \(f(n,k)=(n-k)f(n-1,k-1)+kf(n-1,k)\)
接下来的一步需要神秘观察。
我们发现这个递推式和欧拉数(\(A(n,m)\) 表示长度为 \(n\) 的排列 \(p\),有 \(m\) 个位置满足 \(p_i<p_{i+1}\) 的方案数)的递推式很像,我们通过一些比对可以得出 \(f(n,k)=A(n-1,k-1)\)
我们考虑如何求 \(A(n,i)\)
容斥,钦定有 \(j(j\ge i)\) 个上升位置,然后之后的系数用生成函数(相当于 \(n\) 个点分成 \(n-j\) 个集合,集合内大小关系固定,然后把所有集合都合并起来的方案数)表示:
\(\sum\limits_{j=i}^n(-1)^{j-i}\binom{j}{i}\times n![x^n](e^x-1)^{n-j}\)
\(=\sum\limits_{j=i}^n(-1)^{j-i}\binom{j}{i}\times n![x^n]\sum\limits_{k=0}^{n-j}e^{kx}(-1)^{n-j-k}\binom{n-j}{k}\)
\(=\sum\limits_{j=i}^n(-1)^{j-i}\binom{j}{i}\times n!\sum\limits_{k=0}^{n-j}k^n(-1)^{n-j-k}\binom{n-j}{k}\)
\(=\sum\limits_{k=1}^{n-i}k^n(-1)^{n-i-k}n!\sum\limits_{j=1}^{n-k}\binom{j}{i}\binom{n-j}{k}\)
\(=n!\sum\limits_{k=1}^{n-i}k^n(-1)^{n-i-k}\binom{n+1}{i+k+1}\)
于是我们可以 \(O(n-i)\) 的求出 \(A(n,i)\),我们通过一系列变换也可以 \(O(i)\) 的求出 \(A(n,i)\),但那不重要。
时间复杂度就是 \(O(\sum n\log \mod)\)

点击查看代码
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
template<typename T> void read(T &FF){FF=0;int RR=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;FF*=RR;
}
const int N=400010,P=998244353;
int n,k,fac[N],ifac[N];
int qmi(int x,int y){int res=1;for(;y;y>>=1){ if(y&1) res=1ll*res*x%P;x=1ll*x*x%P;}return res;
}
void comb(int n){fac[0]=1;F(i,1,n) fac[i]=1ll*fac[i-1]*i%P;ifac[n]=qmi(fac[n],P-2);DF(i,n-1,0) ifac[i]=1ll*ifac[i+1]*(i+1)%P;
}
int bin(int x,int y){ if(x<y||y<0) return 0;return 1ll*fac[x]*ifac[y]%P*ifac[x-y]%P;}
int Euler(int n,int k){int res=0;F(i,1,n-k){int val=1ll*qmi(i,n)*bin(n+1,i+k+1)%P;if((n-i-k)&1) res=(res+P-val)%P;else res=(res+val)%P;}return 1ll*res*fac[n]%P;
}
void work(){read(n),read(k);int ans=1ll*Euler(n-1,k-1)*ifac[n]%P*fac[2*n]%P*qmi(qmi(2,n),P-2)%P;printf("%d\n",ans);
}
int main(){comb(N-1);int T;read(T);while(T--) work();return 0;
}
http://www.vanclimg.com/news/543.html

相关文章:

  • 03_Wazuh安装和使用.md
  • 01_pfSense防火墙安装和使用文档
  • 新视角问诊通
  • 寻医问药小程序系统
  • c# ACME client
  • 寻疗智慧 IOT 数字健康服务平台
  • 入职—员工体验的关键时刻,看AI Agent如何将体验值、效率值双双拉满
  • 文件完整性校验工具 CHK 5.51 绿色中文版
  • 2025年7月26日,工信部人才交流中心 CUUG - PGCP/PGCM认证考试完成!
  • 链上充值监听与自动划转资金流程实现 - fox
  • synchronized底层实现是什么 lock底层是什么 有什么区别
  • iOS 性能监控 苹果手机后台运行与能耗采样实战指南
  • pygame打飞机_1展示窗口
  • 个人版Navicat17 Lite版本安装教程(附安装包)2025最新版详细图文安装教程
  • TapData 出席 TDBC 2025 可信数据库发展大会,分享“实时+信创”时代的数据基础设施演进路径
  • AI 是搭子不是替代者:我用大模型工具(cursor,trae)编程的一年经验总结 - IT
  • AIX中为单网卡配置多IP地址
  • NepCTF 2025
  • 【LeetCode 234】回文链表 —— 算法进阶:时间复杂度 O(n),空间复杂度 O (1)
  • Navicat Premium 数据库管理工具 v17.1.10 绿色版
  • 线性筛筛一般积性函数
  • 昨日总结
  • 差分探头都能测那些信号呢?
  • VisualCppRedist 运行库合集 v84
  • word自定义标序号
  • 完整深度学习环境安装指南 (PyTorch 2.7.1 + CUDA 12.8)
  • genieacs脚本配置
  • Nodej - *--_
  • 基于 PKDV508E 高压差分探头的电机反电动势测试方案
  • 数字孪生:驱动工厂智能化转型的核心技术