CF382E
orz sinsop90/bx
乌龟和 sinsop 结芬!!!
题意即数最大匹配为 \(k\) 的二叉树个数。数树问题,考虑不断加入子树 dp。但是这题是二叉树,所以可以直接每次将两个并作一个转移。
考虑怎么设计状态:子树 \(siz\) 肯定是要记的,然后最大匹配数也是。发现只记这两个不好转移,于是再记录当前子树根有没有选的 \(0/1\) 状态。
于是设 \(dp_{i,j,0/1}\) 为当前子树大小为 \(i\),最大匹配为 \(j\),根是/否被选。
考虑转移,首先枚举两棵子树大小 \(i,p\) 及分别的最大匹配 \(j,q\)。先考虑合并后根没有被选,则两棵子树根都已经被选,即:
\[dp_{i+p+1,j+q,0}:=dp_{i+p+1,j+q,0}+dp_{i,j,1}\times dp_{p,q,1}\times\binom{i+p+1}{i}\times\binom{p+1}{p}
\]
后面两个组合数是选定点的标号的方案数。
否则根没有被选,则两个子树至少有一个根没被选。则类似地,有:
\[dp_{i+p+1,j+q+1,1}:=dp_{i+p+1,j+q,1}+dp_{i,j,0/1}\times dp_{p,q,0/1}\times\binom{i+p+1}{i}\times\binom{p+1}{p}
\]
两边不同时为 \(1\)。
还有一点小问题,当 \(i=p\) 时会算重,此时在转移时乘上 \(\dfrac{1}{2}\) 即可。
初始值为 \(dp_{0,0,1}=dp_{1,0,0}=1\),\(ans=\dfrac{1}{n}(dp_{n,m,0}+dp_{n,m,1})\) 因为根为 \(1\)。时间复杂度 \(O(n^4)\)。
code:
点击查看代码
int n,m,fac[N],ifac[N],dp[N][N][2];
il int Mod(int x,int y){return x+y>=mod?x+y-mod:x+y;}
il int binom(int x,int y){return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
il int qpow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod,y>>=1;
}
return ret;
}
void Yorushika(){
scanf("%d%d",&n,&m);
fac[0]=1;
rep(i,1,n)fac[i]=1ll*fac[i-1]*i%mod;
ifac[n]=qpow(fac[n],mod-2);
drep(i,n-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
dp[0][0][1]=dp[1][0][0]=1;
const int iv2=qpow(2,mod-2);
rep(i,1,n-1)rep(j,0,i/2){
rep(p,0,min(n-i,i))rep(q,0,p/2){//I love turtles(It's written by sinsop90!)
int x=i==p?iv2:1;
dp[i+p+1][j+q][0]=Mod(dp[i+p+1][j+q][0],1ll*dp[i][j][1]*dp[p][q][1]%mod*binom(i+p+1,i)%mod*binom(p+1,p)%mod*x%mod);
dp[i+p+1][j+q+1][1]=Mod(dp[i+p+1][j+q+1][1],1ll*dp[i][j][0]*dp[p][q][0]%mod*binom(i+p+1,i)%mod*binom(p+1,p)%mod*x%mod);
dp[i+p+1][j+q+1][1]=Mod(dp[i+p+1][j+q+1][1],1ll*dp[i][j][0]*dp[p][q][1]%mod*binom(i+p+1,i)%mod*binom(p+1,p)%mod*x%mod);
dp[i+p+1][j+q+1][1]=Mod(dp[i+p+1][j+q+1][1],1ll*dp[i][j][1]*dp[p][q][0]%mod*binom(i+p+1,i)%mod*binom(p+1,p)%mod*x%mod);
}
}
printf("%lld\n",1ll*Mod(dp[n][m][0],dp[n][m][1])*qpow(n,mod-2)%mod);
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}

浙公网安备 33010602011771号