WrongAnswer_90

一言(ヒトコト)

[ARC171C] Swap on Tree

My Blogs

[ARC171C] Swap on Tree

科技改变生活。以 6ms 的速度拿下了目前最优解(

如果已经确定了 \(u\) 的一个儿子 \(v\) 内部的操作顺序,考虑在某个时刻交换 \((u,v)\)。设 \(a[1,k]\) 是操作 \(v\) 子树内部时 \(v\) 上面的颜色,可以发现在第 \(i\) 个时刻交换和在第 \(j\) 个时刻交换,方案本质不同的充要条件是 \(a_i\not= a_j\)

考虑 \(i\)\(i\) 的所有儿子,如果选择了 \(S\) 作为要与 \(i\) 交换的子树集合,则权值是 \(|S|!\prod_{i\in S}(\sum_j jf_{i,j})\prod_{i\notin S}(\sum_j f_{i,j})\),其中 \(f_{i,j}\) 表示 \(i\) 子树内颜色改变次数是 \(j\) 的方案数。\(|S|!\) 是因为在确定 \(i\) 和集合内所有点的操作顺序,\(jf_{i,j}\) 是因为对于在集合里的点有颜色切换次数个本质不同的交换方案。

暴力做是 \(\mathcal O(n^2)\) 的。设 \(g_{i,0}=\sum_i f_{x,i},g_{i,1}=\sum_i if_{x,i}\)。设多项式 \(F_u(x)=g_{u,0}+g_{u,1}x\),则 \(f_{u,k+1}\) 即为 \(k![x^k]\prod_{v\in\text{son}(u)}F_v(x)\)

注意到要乘的多项式的总个数是 \(\mathcal O(n)\) 的,所以可以用你喜欢的方法比如分治 NTT 或者先 ln 再 exp 做到 \(\mathcal O(n\log^2 n)\) 或者 \(\mathcal O(n\log n)\)

int n,fr[200010],g[200010][2];
vi T[200010];
vp F;
vi solve(int l,int r)
{
	if(l==r)return {F[l].fi,F[l].se};
	int mid=(l+r)>>1;
	return FFT(solve(l,mid),solve(mid+1,r));
}
void dfs(int x,int fa=0)
{
	for(auto to:T[x])if(to!=fa)dfs(to,x);
	F.clear();
	for(auto to:T[x])if(to!=fa)F.eb(mp(g[to][0],g[to][1]));
	if(F.empty())return g[x][0]=g[x][1]=1,void();
	vi ve=solve(0,F.size()-1);
	for(int i=1;i<=ve.size();++i)Mmul(ve[i-1],fr[i-1]),Madd(g[x][1],Cmul(ve[i-1],i)),Madd(g[x][0],ve[i-1]);
}
inline void mian()
{
	read(n),init(),fr[0]=1;int x,y;
	for(int i=1;i<=n;++i)fr[i]=Cmul(fr[i-1],i);
	for(int i=1;i<n;++i)read(x,y),T[x].eb(y),T[y].eb(x);
	dfs(1),write(g[1][0]);
}
posted @ 2024-09-04 16:13  WrongAnswer_90  阅读(4)  评论(0编辑  收藏  举报