1 条题解

  • 0
    @ 2025-8-24 22:38:04

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Umbrella_Leaf
    曹刘生子,当如孙仲谋。

    搬运于2025-08-24 22:38:04,当前版本为作者最后更新于2022-05-06 21:17:53,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    分析

    f(S)f(S) 表示第一棵树的非叶子集合恰好SS 时构造第一棵树的方案数。

    g(T)g(T) 表示第二棵树的非叶子集合恰好TT 时构造第二棵树的方案数。

    那么答案为

    $$Ans=\sum_{S\cap T=\varnothing,S\cup T=\{1,2,\cdots,n\}}f(S)g(T) $$

    直接求这个不太好求,我们考虑容斥。

    f(S)f'(S) 表示第一棵树的非叶子集合包含于 SS 时构造第一棵树的方案数。

    g(T)g'(T) 表示第二棵树的非叶子集合包含于 TT 时构造第二棵树的方案数。

    $$\begin{aligned} Ans&=\sum_{S\cap T=\varnothing,S\cup T=\{1,2,\cdots,n\}}f(S)g(T)\\&=\sum_{S\cap T=\varnothing,S\cup T=\{1,2,\cdots,n\}}\sum_{S'\subseteq S,T'\subseteq T}f'(S')g'(T')(-1)^{|S|-|S'|+|T|-|T'|} \\&=\sum_{S'\cap T'=\varnothing}f'(S')g'(T')(-1)^{n-|S'|-|T'|}2^{n-|S'|-|T'|}\\&=\sum_{S'\cap T'=\varnothing}f'(S')g'(T')(-2)^{n-|S'|-|T'|} \end{aligned} $$

    其中倒数第二个等号的理由是:不属于 SS'TT' 的那些元素可能在 SS 中,也可能在 TT 中。

    然后可以 DP,我们设 dpi,j,kdp_{i,j,k} 表示确定了 [1,i][1,i] 中的点在 SS'TT' 中的情况,{1,,i}S=j|\{1,\cdots,i\}\cap S'|=j{i+1,,n}T=k|\{i+1,\cdots,n\}\cap T'|=k ,且我们已经为 (1,i](1,i] 选好了第一棵树中的父亲,为 [1,i)[1,i) 选好了第二棵树中的父亲时,这些父亲的方案数。

    初值:k[1,n)\forall k\in[1,n)dp1,1,k=1dp_{1,1,k}=1。因为 11 一定是第一棵树的非叶子节点,也一定是第二棵树的叶子节点,不需要对其进行容斥。

    转移时,分类讨论 iiSS'TT' 中的情况,然后确定 ii 在第一棵树中的父亲和 i1i-1 在第二棵树中的父亲:

    1. ii 属于 SS'dpi1,j,kdp_{i-1,j,k} 转移到 dpi,j+1,kdp_{i,j+1,k},系数为 j×kj\times k
    2. ii 属于 TT'dpi1,j,kdp_{i-1,j,k} 转移到 dpi,j,k1dp_{i,j,k-1},系数为 j×kj\times k
    3. ii 两个都不属于,dpi1,j,kdp_{i-1,j,k} 转移到 dpi,j,kdp_{i,j,k},系数为 2×j×k-2\times j\times k

    其中转移系数中包含 j×kj\times k 的原因是:

    考虑对于一个 SS,如何计算 f(S)f'(S)

    对于节点 i(1,n]i\in(1,n]faifa_i 可能是 [1,i)[1,i) 中的任意一个非叶子节点下面,那么方案数是 [1,i)[1,i) 中非叶子节点的个数,也就是 jj

    g(T)g'(T) 同理,只不过此时我们计算的是 i1i-1 在第二棵树中的父亲方案数,也就是 [i,n][i,n] 中非叶子节点的个数。

    根据乘法原理,只需要将所有这样的点个数乘起来即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    int n;ll mod;
    ll dp[2][505][505];
    int main(){
    	scanf("%d%lld",&n,&mod);
    	for(int i=1;i<n;i++)dp[1][1][i]=1;
    	for(int i=2,now=0;i<=n;i++,now^=1){
    		memset(dp[now],0,sizeof(dp[now]));
    		ll ans=0;
    		for(int j=1;j<i;j++)
    			for(int k=1;k<=n-i+1;k++)if(dp[now^1][j][k]){
    				dp[now][j][k]=(dp[now][j][k]+dp[now^1][j][k]*(mod-2)%mod*j%mod*k%mod)%mod;
    				dp[now][j+1][k]=(dp[now][j+1][k]+dp[now^1][j][k]*j%mod*k%mod)%mod;
    				dp[now][j][k-1]=(dp[now][j][k-1]+dp[now^1][j][k]*j%mod*k%mod)%mod;
    				if(k==1)ans=(ans+dp[now^1][j][k]*j%mod*k%mod)%mod;
    			}
    		printf("%lld\n",ans);
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    7652
    时间
    2000ms
    内存
    1024MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者