CF859E Desk Disorder

题目

CF859E Desk Disorder

分析

牛逼数数题。

首先是个人应该就能想到建图,但是我这个傻逼建的图是 (n^2) 级别的,我怎么建的可以自行想象,暂不赘述。

我们发现,如果我们将每一个位置看做一个点,将题目给出的可以移动的座位 (x->y) 看做一条有向边 ((x,y)) ,那么显然会给出 (n) 条有向边,并且每一个点的出度只能是 (0/1)

这样的图显然只会有几种情况:树,环,基环树,自环。

同时我们发现只有当一个点最开始有人时,才会有出度。

并且,对于两个不同的连通块,它们之间的方案互不影响。

这启示我们对同一连通块的方案数单独求出来,然后用乘法原理求总方案数。

现在考虑几种情况单独的方案数:

对于树来说,如果我们要移动树上某一个点到其父亲,那么其到根的路径上的所有非根节点都要往父亲方向走一步,最后根节点被占据。(因为根节点没有出去的才能作为根节点,说明根节点一开始是空的,而其他节点一开始都一定是有人的。)

那么树的方案数很显然是 (siz[x]) ,其中 (x) 是树的根节点。

对于环来说,如果我们要移动环上的任意一个节点,那么整个环都一定会往前走一步,然后也可以整个环都不动,所以方案数为 (2)

对于基环树来说,其非环上的部分必然不能动,因为这样会出现两个节点去往同一个位置的情况,那么能动的部分其实也只有环上的点,所以与环的情况一样,方案数为 (2)

对于自环来说,其自身必然不动,方案数显然为 (1) (对于存在自环的树显然也不能动,也是 (1))。

答案就是每一个连通块的方案数乘积了,注意维护可以使用并查集,具体见代码。

代码

#include<bits/stdc++.h>
using namespace std;
//#ifdef ONLINE_JUDGE
//	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//	char buf[1<<21],*p1=buf,*p2=buf;
//#endif
template<typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template<typename T>
inline void write(T x){
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
#define ull unsigned long long
#define ld long double
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pc putchar
#define PII pair<int,int>
#define rep(i,x,y) for(register int i=(x);i<=(y);i++)
#define dep(i,y,x) for(register int i=(y);i>=(x);i--)
const int MOD=1e9+7;
inline int inc(int x,int y){x+=y;return x>=MOD?x-MOD:x;}
inline int dec(int x,int y){x-=y;return x<0?x+MOD:x;}
inline void incc(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
inline void decc(int &x,int y){x-=y;if(x<0) x+=MOD;}
inline void chkmin(int &x,int y){if(y<x) x=y;}
inline void chkmax(int &x,int y){if(y>x) x=y;}
const int N=2e5+5,M=1e6+5,INF=1e9+7;
int n,fa[N],fl1[N],fl2[N],siz[N],Ans=1;
int Getfa(int x){return x==fa[x]?x:fa[x]=Getfa(fa[x]);}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(false);
//	double ST=clock();
	read(n);
	rep(i,1,n*2) fa[i]=i,siz[i]=1;
	rep(i,1,n){
		int x,y,tp=false;read(x),read(y);
		if(x==y) fl2[x]=true;
		x=Getfa(x),y=Getfa(y);
		if(x==y) fl1[x]=true;
		else fl2[y]|=fl2[x],fa[x]=y,siz[y]+=siz[x],siz[x]=0;
	}
	rep(i,1,n*2) if(Getfa(i)==i&&!fl2[i]) Ans=1ll*Ans*(fl1[i]?2:siz[i])%MOD;
	write(Ans);
//#ifndef ONLINE_JUDGE
//	cerr<<"
Time:"<<(clock()-ST)/CLOCKS_PER_SEC<<"s
";
//#endif
	return 0;
}
/*
4
1 2
2 3
3 3
4 3
*/



原文地址:https://www.cnblogs.com/Akmaey/p/15477808.html