AGC060C Large Heap 题解 / 计数 dp

题目传送门:AGC060C Large Heap

首先这个东西完全就是一个满二叉树的堆,相当于权值顺序要为一个拓扑,且 \(U\)\(V\) 前面。

\(U,V\)\(A+1\)\(B+1\) 层的最左和左右端点。

那么 \(U,V\) 分别是两条最左或最右的链。

而拓扑序的开头一定为 \(1\),分成两棵树,然后再找一个根再分裂,那么我们只需要考虑存在 \(U,V\) 的树,剩下的随便填即可,那么最主要的就是存在 \(U,V\) 的两棵树的深度。

考虑 dp,设 \(s_i\) 表示深度为 \(i\) 满二叉树拓扑方案数,\(g_{i,j}\) 表示两棵树的深度分别为 \(i,j\) 的方案数,\(f_{i,j}\) 表示概率。

转移的话考虑选择左右那个树。

\[s_i = s_{i-1}^2 C_{2^i-2}^{2^{i-1}-1} \]

\[g_{i,j}=g_{i-1,j} s_{i-1} C_{2^i+2^j-3}^{2^{i-1}-1} + g_{i,j-1}s_{j-1}C_{2^i+2^j-3}^{2^j-1} \]

\[f_{i,j}=\frac{g_{i,j}}{s_is_jC_{2^i+2^j-2}^{2^i-1}} \]

\(g_{i,j}\) 代入 \(f_{i,j}\) 并用 \(f\) 表示 \(g\) 化简可得

\[f_{i,j}=f_{i-1,j}\frac{2^i-1}{2^i+2^j-2} + f_{i,j-1}\frac{2^j-1}{2^i+2^j-2} \]

显然初始时 \(f_{n-A-1,j}=1\) 其中 \(j\ge n-B\)

#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read(){
	char c=getchar();
	int f=1,ans=0;
	while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
	return ans*f;
}
const int N=5010,mod=998244353;
int f[N][N],A,B,n,g[N];
void exgcd(int a,int b,int &x,int &y){
	if (b==0) x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
inline int inv(int a){
	int x,y;
	exgcd(a,mod,x,y);
	return (x%mod+mod)%mod;
}
inline void add(int &x,int y){x=(x+y)%mod;}
main(){
	n=read(),A=read(),B=read();
	g[0]=1;for (int i=1;i<=n;i++) g[i]=g[i-1]*2%mod;
	for (int i=n-B;i<=n;i++) f[n-A-1][i]=1;
	for (int i=n-A;i<=n;i++) for (int j=n-B;j<=n;j++)
		add(f[i][j],f[i-1][j]*(g[i]-1+mod)%mod*inv(g[i]+g[j]-2+mod)%mod+f[i][j-1]*(g[j]-1+mod)%mod*inv(g[i]+g[j]-2+mod)%mod);
	cout <<f[n-1][n-1];
    return 0;
}
posted @ 2026-01-17 18:31  OTn53_qwq  阅读(22)  评论(0)    收藏  举报