题解:P8329 [ZJOI2022] 树
提供一种不需要容斥的做法。
思路
考虑枚举每个点是否是叶子结点,设
对于一棵树,可以使用 dp 计算方案数。设
可以发现这个 dp 本质上计算的是:对于每个满足
发现这个过程是可以倒推的,所以直接将这两棵树当前的
实现的时候可以将
代码
#include<bits/stdc++.h>
using namespace std;
int dj[]={-1,-1,0,0,0,0,1,1};
int dk[]={-1,0,-1,0,0,1,0,1};
int n,mod;
long long dp[2][501][501];
int main()
{
cin>>n>>mod;
dp[0][0][0]=1;
for(int i=1; i<=n; ++i)
{
memset(dp[i&1],0,sizeof(dp[i&1]));
for(int j=0; j<=i; ++j)
{
for(int k=0; k<=n-i; ++k)
{
for(int l=0; l<8; ++l)
{
int tj=j+dj[l],tk=k+dk[l];
if(tj<0 || tk<0) continue;
dp[i&1][j][k]+=dp[i-1&1][tj][tk]*(i==1?1:tj);
}
dp[i&1][j][k]=dp[i&1][j][k]*k%mod;
}
}
if(i!=1)
{
int j=0,k=0; long long ans=0;
for(int l=0; l<8; ++l)
{
int tj=j+dj[l],tk=k+dk[l];
if(tj<0 || tk<0) continue;
ans=(ans+dp[i-1&1][tj][tk]*tj)%mod;
}
cout<<ans<<'\n';
}
}
return 0;
}