Codeforces 1707D. Partial Virtual Trees (3000)

给定一棵以 \(1\) 为根的有根树,有一个集合 \(S=\{1,2,\dots,n\}\)。可以对这个集合进行如下操作:
选择一个集合 \(T\),满足 \(T\subsetneq S\),且 \(\forall x\neq y\in T,\text{lca}(x,y)\in T\)。令 \(S\gets T\)
对于 \(k=1\sim n-1\) 求出有多少种方式使得恰好操作 \(k\) 次之后,\(S=\{1\}\),答案对给定模数 \(p\) 取模。
\(1\leq n\leq 2000,10^8+7\le p\le 10^9+9\)


首先考虑将 \(S_1\neq S_2\) 的限制去掉,若去掉后求得的答案为 \(f_n\),原答案为 \(ans_n\),则有

\[f_n=\sum_{i=1}^{n}\binom{n}{i} ans_i \]

即考虑其中 \(i\)\(S_1\neq S_2\)。移项则有

\[ans_n=f_n-\sum_{i=0}^{n-1}\binom{n}{i}ans_i \]

那么问题转化成了求解 \(f_n\),题目中的条件也就是保持 \(S_1\) 中的点组成一个连通块,那么节点 \(x\) 可被删当且仅当 \(x\) 的所有子节点为根的子树都被删光或者除了以 \(x\) 某个子节点 \(v\) 为根的子树没被删光,其余整个树所有节点都被删光。

\(dp_{x,t}\) 表示以 \(x\) 为根的子树在 \(t\) 时刻恰好被删光的方案数。则有

\[dp_{x,t}=\prod_{v\in son_x}\big(\sum_{p\le t} dp_{v,p}\big{)}+\sum_{v\in son_x}dp_{v,t}\sum_{p<t}\prod_{u\in son_x\bigcap u\neq v}\big(\sum_{q\le p}dp_{u,q}\big) \]

分别为考虑 \(x\) 在时刻 \(t\) 被删光以及以 \(x\) 的某个子节点 \(v\) 为根的子树最后被删光的方案数。

\(s_{x,t}=\sum\limits_{p\le t}dp_{x,p},g_{x,t}=\prod\limits_{v\in son_x}s_{v,t}\),然后使用树形 \(\text{dp}\) 解决,总时间复杂度 \(O(n^2)\)

\(\color{blue}{\text{code}}\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2005;
int n,mod;ll fac[N],inv[N],Inv[N],ans[N],pmul[N][N],smul[N][N],s[N][N],dp[N][N];
vector<int>G[N];
inline ll qpow(ll a,ll b){
	ll ans=1;
	for(;b;b>>=1,a=a*a%mod)if(b&1)ans=ans*a%mod;
	return ans;
}
inline void precalc(int n){
	fac[0]=inv[0]=Inv[0]=fac[1]=inv[1]=Inv[1]=1;
	for(int i=2;i<=n;++i)
		fac[i]=fac[i-1]*i%mod,
		Inv[i]=(mod-mod/i)*Inv[mod%i]%mod,
		inv[i]=inv[i-1]*Inv[i]%mod;
}
inline ll C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline void dfs(int x,int fa){
	vector<int>son;
	for(auto y:G[x])if(y^fa)dfs(y,x),son.emplace_back(y);
	if(son.empty()){
		for(int i=1;i<=n;++i)dp[x][i]=1,s[x][i]=i;
		return;
	}
	for(int t=1;t<=n;++t){
		pmul[0][t]=s[son[0]][t],smul[son.size()][t]=1;
		for(int id=1;id<son.size();++id)
			pmul[id][t]=pmul[id-1][t]*s[son[id]][t]%mod;
		for(int id=(int)son.size()-1;~id;--id)
			smul[id][t]=smul[id+1][t]*s[son[id]][t]%mod;
	}
	for(int t=1;t<=n;++t)dp[x][t]=smul[0][t];
	if(x^1)for(int v=0;v<son.size();++v){
		ll S=0;
		for(int t=1;t<=n;++t){
			(dp[x][t]+=dp[son[v]][t]*S)%=mod;
			(S+=(v>0?pmul[v-1][t]:1)*smul[v+1][t])%=mod;
		}
	}
	for(int i=0;i<=son.size();++i)
		for(int t=0;t<=n;++t)
			pmul[i][t]=smul[i][t]=1;
	for(int t=1;t<=n;++t)(s[x][t]=s[x][t-1]+dp[x][t])%=mod;
}
int main(){
	scanf("%d%d",&n,&mod),precalc(N-1);
	for(int i=1,x,y;i<n;++i)scanf("%d%d",&x,&y),G[x].emplace_back(y),G[y].emplace_back(x);
	dfs(1,0);
	for(int t=1;t<n;++t){
		ans[t]=dp[1][t];
		for(int i=0;i<t;++i)(ans[t]+=mod-C(t,i)*ans[i]%mod)%=mod;
		printf("%lld ",ans[t]);
	}
	return 0;
}
posted @ 2022-07-24 16:23  Samsara-soul  阅读(50)  评论(0编辑  收藏  举报