卧薪尝胆,厚积薄发。
Desk Disorder
Date: Tue Nov 06 09:32:58 CST 2018 In Category: NoCategory

Description:

每个人有两个想坐的凳子,问有多少种方案使得所有人都坐在想坐的凳子上。
$1\leqslant n\leqslant 10^5$

Solution:

把人看成边,凳子看成点,得到一个图,求出所有的联通块,由于是联通块,所以 $v\leqslant e + 1$ ,由于当 $v<e$ 时无解,所以一定有 $v-1=e$ 或 $v=e$ ,当第一种情况时是一棵树,那么如果强制一个点不选其他所有点就确定了,因此答案为点数,第二种情况的话,如果环大小 $>1$ ,那么方案数为 $2$ ,否则一定有自环,方案数为 $1$ 。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n;
#define MAXN 200010
int f[MAXN],g[MAXN],siz[MAXN];
bool tag[MAXN];
int find(int x){return (x == f[x] ? x : f[x] = find(f[x]));}
bool vis[MAXN];
#define MOD 1000000007
int main()
{
scanf("%d",&n);
for(int i = 1;i <= 2 * n;++i)
{
f[i] = i;
siz[i] = 1;
tag[i] = false;
}
int a,b;
for(int i = 1;i <= n;++i)
{
scanf("%d%d",&a,&b);
int p = find(a),q = find(b);
if(p == q)
{
++g[p];
if(a == b)tag[p] = true;
}
else
{
f[p] = q;
g[q] += g[p] + 1;
siz[q] += siz[p];
tag[q] |= tag[p];
}
}
int ans = 1;
for(int i = 1;i <= 2 * n;++i)
{
int p = find(i);
if(vis[p])continue;
vis[p] = true;
if(g[p] == 0)continue;
if(g[p] > siz[p])
{
puts("0");
return 0;
}
if(g[p] == siz[p] && !tag[p])
{
ans = 1ll * ans * 2 % MOD;
}
if(g[p] + 1 == siz[p])
{
ans = 1ll * ans * siz[p] % MOD;
}
}
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡