ARC083F Collecting Balls

题解

Posted by WrongAnswer_90's Blog on August 23, 2024

My Blogs

[ARC083F] Collecting Balls

建图,连边 $(x_i,y_i+n)$,这样会形成一个基环树森林。对于基环树的每条边,需要把他归到他连接的两个点中任意一个,并且每个点只能拥有一条边。

对于每个基环树分别计算,树边归属的点一定是它两端深度较大的那个,环边归属点整体只有两种方式:顺时针和逆时针。确定了边挂在哪个点上之后,操作顺序的限制就是,如果边 $(x,y)$ 归到了点 $y$,则要求所有 $(y,z),z<x$ 的边需要在它之前操作。

把边看成点,再建一个图来表示拓扑关系:$(x,y)$ 表示 $x$ 需要在 $y$ 之前进行操作。不难证明这是一个森林:对于树边之间显然只有从下到上的边,环边上的边形成了若干条单向链,还有一些环边指向树边的边,所以一定是外向树森林。

然后是非常典的外向树拓扑序计数。对于点 $i$,自己需要放到最前面,然后儿子之间是随意排的,设 $f_i$ 表示 $i$ 子树内拓扑序数量,则:

\[f_i=\prod f_{to}\frac{(siz_i-1)!}{\prod siz_{to}!}\]

右边的分数是一个组合数系数,表示儿子之间可以任意排列。所以每个点的贡献恰好就是 $\frac {1}{siz_i}$。一个外向树森林的答案就是 $\frac{n!}{\prod siz_i}$。总复杂度 $\mathcal O(n)$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
en,sum,sz,ans=1,b[200010],fr[200010],inv[200010];
vector<pii> T[200010];
vi G[200010],ve;
int vis[200010],deg[200010],siz[200010],Id[200010];
stack<int> st;
void dfs0(int x)
{
	vis[x]=1,sz+=2,sz-=T[x].size();
	for(auto [to,v]:T[x])
	{
		ve.eb(v);
		if(!vis[to])dfs0(to);
	}
}
void dfs(int x,int fa=0)
{
	st.e(x),vis[x]=2;
	for(auto [to,v]:T[x])if(to!=fa)
	{
		if(vis[to]==2)
		{
			while(st.top()!=to)b[++len]=st.top(),st.pop();
			b[++len]=to;
			return;
		}
		else dfs(to,x);
		if(len)return;
	}
	st.pop();
}
void dfs1(int x,int fa=0,int from=0)
{
	for(auto [to,v]:T[x])if(to!=fa&&vis[to]<3)
	{
		if(to<fa)G[from].eb(v),++deg[v];
		dfs1(to,x,v);
	}
}
void dfs2(int p)
{
	siz[p]=1;
	for(auto to:G[p])dfs2(to),siz[p]+=siz[to];
	Mmul(sum,inv[siz[p]]);
}
inline void mian()
{
	read(n),fr[0]=inv[0]=1;int x,y,val,S;
	for(int i=1;i<=2*n;++i)fr[i]=Cmul(fr[i-1],i);
	inv[2*n]=power(fr[2*n],MOD-2);
	S=fr[2*n];
	for(int i=2*n-1;i>0;--i)inv[i]=Cmul(inv[i+1],i+1);
	for(int i=1;i<=2*n;++i)Mmul(inv[i],fr[i-1]);
	for(int i=1;i<=2*n;++i)read(x,y),T[x].eb(mp(y+n,i)),T[y+n].eb(mp(x,i));
	for(int i=1;i<=2*n;++i)if(!vis[i])
	{
		len=sz=0,ve.clear(),dfs0(i),sort(ve.begin(),ve.end());
		ve.resize(unique(ve.begin(),ve.end())-ve.begin());
		if(sz!=0){puts("0");return;}
		Mmul(S,power(fr[ve.size()],MOD-2));
		dfs(i),b[len+1]=b[1],b[0]=b[len];
		for(int i=1;i<=len;++i)vis[b[i]]=3;
		for(int i=1;i<=len;++i)//right
		{
			int id=-1;
			for(auto [to,v]:T[b[i]])if(to==b[i-1]){id=v;break;}
			assert(id!=-1),dfs1(b[i],b[i-1],id),Id[i]=id;
		}
		Id[len+1]=Id[1];
		for(int i=0;i<len;++i)if(b[i+2]<b[i])
		G[Id[i+1]].eb(Id[i+2]),++deg[Id[i+2]];
		sum=fr[ve.size()];
		for(auto p:ve)if(!deg[p])dfs2(p);
		for(auto p:ve)G[p].clear(),deg[p]=0;
		val=sum,sum=fr[ve.size()];
		for(int i=1;i<=len;++i)
		{
			int id=-1;
			for(auto [to,v]:T[b[i]])if(to==b[i+1]){id=v;break;}
			assert(id!=-1),dfs1(b[i],b[i+1],id),Id[i]=id;
		}
		Id[0]=Id[len];
		for(int i=0;i<len;++i)if(b[i]<b[i+2])
		G[Id[i+1]].eb(Id[i]),++deg[Id[i]];
		for(auto p:ve)if(!deg[p])dfs2(p);
		Mmul(ans,Cadd(val,sum));
	}
	write(Cmul(S,ans));
}