1 条题解

  • 0
    @ 2026-5-13 9:12:32

    Problem Link

    题目大意

    对于两棵树 T1,T2T_1,T_2,定义 fi(S)f_i(S) 表示 SSTiT_i 上的导出子图的叶子个数。

    定义 T1T2T_1\preccurlyeq T_2 当且仅当 S2V\forall S_2\subseteq V 均存在 S2S1S_2\subseteq S_1 使得 f2(S2)f1(S1)f_2(S_2)\ge f_1(S_1)

    如果 T1T2T_1\preccurlyeq T_2T2T1T_2\preccurlyeq T_1,那么认为 T1,T2T_1,T_2 等价。

    给定 kk 棵树 T1TkT_1\sim T_k,求 T1TkTT_1\sim T_k\preccurlyeq TTT 的数量,以及 TT1TkT\preccurlyeq T_1\sim T_kTT 构成的等价类数量。

    数据范围:n5000,k1000n\le 5000,k\le 1000

    思路分析

    先分析题目中给出的这个偏序关系:

    Vi(S)V_i(S) 表示 SSTiT_i 上的斯坦纳树点集,首先我们观察 fi(S)f_i(S) 的超集最小值,一个自然的观察是最小值在 Vi(S)V_i(S) 取到。

    证明是简单的,考虑 Vi(S)V_i(S) 上的每个叶子,一定是 SS 的叶子,那么 SS 的每个超集一定包含这些叶子,在每个叶子以及其外面的点中至少有一个叶子,因此 fi(S)f_i(S) 的超集最小值就是 fi(Vi(S))f_i(V_i(S)),记为 gi(S)g_i(S)

    那么限制就变成 f2(S)g1(S)f_2(S)\ge g_1(S),注意到 gg 有单调性,即 ST    g(S)g(T)S\subseteq T \implies g(S)\le g(T),证明就是上面的过程,g(S)g(T)g(S)\subseteq g(T),而 g(S)g(S)f(S)f(S) 的超集最小值。

    那么我们把 SS 变成 V2(S)V_2(S),会减小右侧限制增大左侧限制,那么只要在 T2T_2 上联通的 SS 是否有 f2(S)g1(S)f_2(S)\ge g_1(S) 即可。

    一个核心观察是,我们只要考虑 f2(S)=2f_2(S)=2 的点合法,那么就能得到 T1T2T_1\preccurlyeq T_2,证明如下:

    首先 f2(S)=1f_2(S)=1 的点显然总是成立。

    然后用数学归纳法,我们已知 f2(S)kf_2(S)\le kSS 都合法,现在要证明 f2(S)=k+1f_2(S)=k+1SS 都合法。

    不妨假设 SS'SS 中选取 kk 个叶子生成的斯坦纳树,则 k=f2(S)g1(S)k=f_2(S')\ge g_1(S')

    观察 SSS\setminus S',其形态是一条过某个叶子 xx 的链,取一个 SS' 中的叶子 yy,则 S=SV2({x,y})S=S'\cup V_2(\{x,y\})

    C=V2({x,y})C=V_2(\{x,y\}),由于 f2(C)=2f_2(C)=2,因此 g1(C)f2(C)=2g_1(C)\le f_2(C)=2,那么 V1(C)V_1(C) 也是一条链。

    因为 yv1(S)V1(C)y\in v_1(S')\cap V_1(C),所以 V1(S)=V1(S)V1(C)V_1(S)=V_1(S')\cup V_1(C),从而 g1(S)g1(S)+g1(C)k+2g_1(S)\le g_1(S)+g_1(C)\le k+2

    现在要证明 V1(S)V_1(S') 并上 V1(C)V_1(C) 的过程能删掉 V1(S)V_1(S’) 中的一个叶子。

    这是简单的,考虑离 xx 最近的叶子 zz,由于 yV1(S)y\in V_1(S'),那么 zV1(C)z\in V_1(C),则 zzV1(S)V_1(S) 中不是叶子。

    所以 g1(S)k+1g_1(S)\le k+1,证毕。

    那么 T1T2T_1\preccurlyeq T_2 当且仅当 T2T_2 中每条链在 T1T_1 中也是一条链的子集。

    我们有一种好的方法刻画这个限制,定义 G(T)G(T){(u,v)g(u,v)=2}\{(u,v)\mid g(u,v)=2\},即将 TT 中的每个链变成一个团,此时 T1T2    G(T2)G(T1)T_1\preccurlyeq T_2\iff G(T_2)\subseteq G(T_1)

    证明如下:

    首先考虑充分性,建出 GG 的圆方树,此时 T1T_1 上的一条链在其圆方树上也是一条链,而 G(T2)G(T_2) 的圆方树可以由 G(T1)G(T_1) 的圆方树合并若干方点得到,则其在 T2T_2 上也是一条链。

    否则考虑 (u,v)G(T2)G(T1)(u,v)\in G(T_2)\setminus G(T_1),此时 V2({u,v})V_2(\{u,v\})T2T_2 上是一条无分支的链,那么对于任意 wwg2({u,v,w})=2g_2(\{u,v,w\})=2

    由于 (u,v)∉G(T1)(u,v)\not\in G(T_1),因此 u,vu,v 路径上存在一个非二度点,取他的另一个邻居 ww,则 g1({u,v,w})3g_1(\{u,v,w\})\ge 3

    选取点集 V2({u,v,w})V_2(\{u,v,w\}) 即导出矛盾。证毕。

    那么先解决问题二,bitset 求出 G=G(Ti)G=\bigcap G(T_i),则 G(T)GG(T)\subseteq G

    首先 GG 必须连通,对 GG 建立圆方树,容易证明每个点双连通分量都是团,那么限制就是 GG 每个点双连通分量在 TT 连通,对每个点双求生成树个数乘起来。

    然后是问题一,依然求 G=G(Ti)G=\bigcup G(T_i) 的圆方树,这个不用 bitset,把 G(Ti)G(T_i) 中的团当成环,然后求圆方树即可。

    现在我们有一棵圆方树,可能的操作就是合并一些相邻的方点,要求是:每个圆点度数 2\ne 2,每个方点至多和两个非叶节点相连。

    可以考虑圆方树上 dp,fu,if_{u,i} 表示 uu 所在的方点中有 ii 个非叶节点,其中 i[0,2]i\in[0,2],具体来说:

    • 如果 uu 是方点,那么 ii 表示 uu 所在的新方点有 ii 个非叶节点。
    • 如果 uu 是圆点,那么 ii 表示 fa(u)fa(u) 所在的新方点会增加 ii 个非叶节点(可能把 uu 的儿子和 fa(u)fa(u) 合并)。

    那么对于方点的转移,直接子树卷积即可。

    对于圆点,我们分析儿子的方点会合并成什么结构,首先如果合并出一个有两个非叶节点的方点,那么 uu 必须是叶子,即此时 uu 的所有邻居都得合并。

    所以我们先子树卷积算出 i=2\sum i=2 的方案。

    剩下的情况,我们用 gx,yg_{x,y} 表示合并出 xx 个没有非叶节点的方点,yy 个恰有一个非叶节点的方点。

    然后考虑转移:

    • x+y=1x+y=1:此时儿子的方点必须和 fa(u)fa(u) 合并,否则 deg(u)=2\deg(u)=2,转移到 fu,yf_{u,y}
    • x+y=2x+y=2:此时儿子的方点不能和 fa(u)fa(u) 合并,转移到 fu,1f_{u,1}
    • x+y>2x+y>2:可以任意选择是否有儿子和 fa(u)fa(u) 合并:
      • 不合并:gx,yfu,1g_{x,y}\to f_{u,1}
      • 合并一个零度点:xgx,yfu,1xg_{x,y}\to f_{u,1}
      • 合并一个一度点:ygx,yfu,2yg_{x,y}\to f_{u,2}

    暴力转移 gx,yg_{x,y} 的复杂度是 O(n3)\mathcal O(n^3) 的。

    注意到 x+y2x+y\le 2 的转移是平凡的,我们只要维护 gx,y,xgx,y,ygx,y\sum g_{x,y},\sum xg_{x,y},\sum yg_{x,y},然后对于 x+y2x+y\le 2 的点重算贡献。

    直接用组合计数的方法维护,hih_i 表示 uu 子树中恰有 ii 个儿子有一个非叶子节点。

    uu 共有 dd 个儿子,枚举有 jj 个零度点和他们合并,方案数为 hi×(dij)×ijh_{i}\times\binom{d-i}j\times i^j,对于 gk,ig_{k,i} 的贡献就是 $h_{i}\times\binom{d-i}j\times i^j\times\begin{Bmatrix}d-i-j\\k\end{Bmatrix}$。

    因此维护答案只要预处理第二类斯特林数的行和,以及每行 ×j\times j 的和。

    时间复杂度 O(nk+n2+n2kω)\mathcal O\left(nk+n^2+\dfrac{n^2k}{\omega}\right)

    代码呈现

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int MAXN=5005,MOD=998244353;
    ll ksm(ll a,ll b=MOD-2) { ll s=1; for(;b;a=a*a%MOD,b>>=1) if(b&1) s=s*a%MOD; return s; }
    int ty,q,n;
    bitset <MAXN> ch,U[MAXN],V[MAXN];
    vector <int> G[MAXN],E[MAXN*2];
    int st[MAXN],tp,dfn[MAXN],low[MAXN],dcnt,vc;
    bool ins[MAXN];
    void dfs0(int u,int fz) {
    	ch.set(u),st[++tp]=u;
    	if(G[u].size()==2) return dfs0(G[u][0]^G[u][1]^fz,u);
    	if(fz) {
    		if(ty==0) {
    			for(int i=1;i<=tp;++i) V[st[i]][st[i%tp+1]]=V[st[i%tp+1]][st[i]]=1;
    			tp=0;
    		} else {
    			while(tp) U[st[tp--]]|=ch;
    			ch.reset();
    		}
    	}
    	for(int v:G[u]) if(v^fz) ch.set(u),st[++tp]=u,dfs0(v,u);
    }
    void link(int u,int v) { E[u].push_back(v),E[v].push_back(u); }
    void tarjan(int u,int fz) {
    	dfn[u]=low[u]=++dcnt,st[++tp]=u,ins[u]=true;
    	for(int v:G[u]) if(v^fz) {
    		if(!dfn[v]) {
    			tarjan(v,u),low[u]=min(low[u],low[v]);
    			if(low[v]>=dfn[u]) {
    				link(++vc,u);
    				while(ins[v]) link(vc,st[tp]),ins[st[tp--]]=false;
    			}
    		} else low[u]=min(low[u],dfn[v]);
    	}
    }
    int C[MAXN][MAXN],pw[MAXN][MAXN];
    int S[MAXN][MAXN],s1[MAXN],s2[MAXN];
    ll f[MAXN*2][3],g[4][4],h[MAXN];
    void dfs1(int u,int fz) {
    	int m=0; f[u][0]=1;
    	for(int v:E[u]) if(v^fz) {
    		dfs1(v,u),++m;
    		f[u][2]=(f[u][2]*f[v][0]+f[u][1]*f[v][1]+f[u][0]*f[v][2])%MOD;
    		f[u][1]=(f[u][1]*f[v][0]+f[u][0]*f[v][1])%MOD,f[u][0]=f[u][0]*f[v][0]%MOD;
    	}
    	if(u>n||!m) return ;
    	f[u][0]=f[u][1]=0;
    	memset(g,0,sizeof(g)),g[0][0]=1;
    	memset(h,0,sizeof(h)),h[0]=1;
    	for(int v:E[u]) if(v^fz) {
    		ll x=f[v][0],y=f[v][1];
    		for(int i=2;i>=0;--i) for(int j=2-i;j>=0;--j) if(g[i][j]) {
    			g[i+1][j]=(g[i+1][j]+g[i][j]*y)%MOD;
    			g[i][j+1]=(g[i][j+1]+g[i][j]*x)%MOD;
    			if(j>0) g[i+1][j-1]=(g[i+1][j-1]+g[i][j]*y%MOD*j)%MOD;
    			g[i][j]=g[i][j]*x%MOD*(i+j)%MOD;
    		}
    		for(int i=m;i>=0;--i) if(h[i]) h[i+1]=(h[i+1]+h[i]*y)%MOD,h[i]=h[i]*x%MOD;
    	}
    	for(int i=0;i<=m;++i) for(int j=0;i+j<=m;++j) {
    		ll z=h[i]*C[m-i][j]%MOD*pw[i][j]%MOD;
    		f[u][1]=(f[u][1]+(s1[m-i-j]+s2[m-i-j])*z)%MOD;
    		f[u][2]=(f[u][2]+1ll*s1[m-i-j]*i%MOD*z)%MOD;
    	}
    	for(int i=0;i<=2;++i) for(int j=0;i+j<=2;++j) if(g[i][j]) {
    		if(i+j==1) f[u][i]=(f[u][i]+g[i][j])%MOD;
    		else if(i+j==2) f[u][1]=(f[u][1]+g[i][j])%MOD;
    		f[u][1]=(f[u][1]+(MOD-g[i][j])*(j+1))%MOD;
    		f[u][2]=(f[u][2]+(MOD-g[i][j])*i)%MOD;
    	}
    }
    signed main() {
    	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    	cin>>ty>>q>>n;
    	if(ty==1) for(int i=1;i<=n;++i) V[i].set();
    	while(q--) {
    		for(int i=1,u,v;i<n;++i) cin>>u>>v,G[u].push_back(v),G[v].push_back(u);
    		for(int i=1;i<=n;++i) if(G[i].size()!=2) { dfs0(i,0); break; }
    		if(ty==1) for(int i=1;i<=n;++i) V[i]&=U[i],U[i].reset();
    		for(int i=1;i<=n;++i) G[i].clear();
    	}
    	for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j&&V[i][j]) G[i].push_back(j);
    	vc=n,tarjan(1,0);
    	if(ty==1) {
    		for(int i=1;i<=n;++i) if(!dfn[i]) return cout<<"0\n",0;
    		ll ans=1;
    		for(int i=n+1;i<=vc;++i) if(E[i].size()>1) ans=ans*ksm(E[i].size(),E[i].size()-2)%MOD;
    		return cout<<ans<<"\n",0;
    	}
    	for(int i=0;i<=n;++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    	for(int i=0;i<=n;++i) for(int j=pw[i][0]=1;j<=n;++j) pw[i][j]=1ll*pw[i][j-1]*i%MOD;
    	for(int i=0;i<=n;++i) {
    		S[i][0]=!i;
    		for(int j=1;j<=i;++j) S[i][j]=(1ll*S[i-1][j]*j+S[i-1][j-1])%MOD;
    		for(int j=0;j<=i;++j) s1[i]=(s1[i]+S[i][j])%MOD,s2[i]=(s2[i]+1ll*S[i][j]*j)%MOD;
    	}
    	for(int i=1;i<=n;++i) if(E[i].size()==1) {
    		dfs1(i,0),cout<<(f[i][0]+f[i][1]+f[i][2])%MOD<<"\n";
    		return 0;
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    8979
    时间
    3000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者