Once and again telling a story lost in time
精妙的 DP 题。
先考虑一点抛弃大脑的东西:\(ans = \sum_{S \cap T = \varnothing, S\cup T = [1,n]} f(S)\cdot g(T)\)。其中,\(f(S)\) 定义为在第一棵树中,不为叶子的节点的集合为 \(S\) 的方案数。\(g(T)\) 定义为在第二棵树中,不为叶子的节点的集合为 \(T\) 的方案数。
显然这个东西完全无法维护,套路的,我们定义 \(f'(S)=\sum_{S' \subseteq S} f(S')\),因此有 \(f(S) = \sum_{S' \subseteq S} (-1)^{|S|-|S'|} f'(S')\)。
所以我们有:
\[\begin{aligned}
ans
&=\sum_{S \cap T = \varnothing, S\cup T = [1,n]} f(S)\cdot g(T)\\
&=\sum_{S \cap T=\varnothing,S\cup T=[1,n]} \sum_{S' \subseteq S} \sum_{T' \subseteq T} {(-1)}^{n-|S'|-|T'|} f'(S') g'(T')\\
&=\sum_{S' \cap T' = \varnothing} {(-1)}^{n-|S'|-|T'|} f'(S')g'(T')\cdot 2^{n-|S'|-|T'|}\\
&=\sum_{S' \cap T' = \varnothing} {(-2)}^{n-|S'|-|T'|} f'(S')g'(T')
\end{aligned}
\]
同时,我们不难得到的是:\(f'(S) = \sum_{i=2}^{n} |S\cap [1,i-1]|\)。对于 \(g'\) 和是同理的。
于是设计 dp 状态 \(dp[i][j][k]\) 表示前 \(i\) 个节点,\(|S \cap [1,i]| = j\),\(|T \cap [i+1,n]|=k\),同时确定了 \((1,i]\) 在第一个树的父亲,\([1,i)\) 在第二个树的父亲的方案数。
考虑这个 dp 怎么转移。不妨分成三种:节点 \(i+1\) 最后属于了 \(S\),最后属于了 \(T\),什么都不属于。因此转移如下:
- \(f[i+1][j+1][k]+=f[i][j][k]\cdot j \cdot k\)
- \(f[i+1][j][k-1]+=f[i][j][k]\cdot j\cdot k\)
- \(f[i+1][j][k]-=2\times f[i][j][k]\cdot j \cdot k\)
Code
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
#define ull unsigned long long
const int N = 505;
int n;
ull mod;
ull f[N][N],g[N][N];
void add(ull &a,ull b){
a += b;
if(a > mod) a -= mod;
}
int main(){
IOS;
cin >> n >> mod;
for(int i=1;i<n;i++)
f[1][i] = 1;
for(int i=2;i<=n;i++){
ull ans = 0;
for(int j=1;j<i;j++)
ans = (ans + f[j][1] * j % mod) % mod;
cout << ans << "\n";
for(int j=1;j<i;j++){
for(int k=1;k<=n-i+1;k++){
ull base = f[j][k] * j % mod;
add(g[j+1][k] , base * k % mod);
add(g[j][k-1] , base * k % mod);
add(g[j][k] , (mod - 2) * base % mod * k % mod);
}
}
swap(f,g);
memset(g,0,sizeof g);
}
return 0;
}

浙公网安备 33010602011771号