【问题背景】
高三的学长们就要离开学校,各奔东西了。某班n人在举行最后的离别晚餐时,饭店老板觉得十分纠结。因为有m名学生偷偷找他,要求和自己暗恋的同学坐在一起。
【问题描述】
饭店给这些同学提供了一个很长的桌子,除了两头的同学,每一个同学都与两个同学相邻(即坐成一排)。给出所有信息,满足所有人的要求,求安排的方案总数(这个数字可能很大,请输出方案总数取余989381的值,也可能为0)。
高三的学长们就要离开学校,各奔东西了。某班n人在举行最后的离别晚餐时,饭店老板觉得十分纠结。因为有m名学生偷偷找他,要求和自己暗恋的同学坐在一起。
【问题描述】
饭店给这些同学提供了一个很长的桌子,除了两头的同学,每一个同学都与两个同学相邻(即坐成一排)。给出所有信息,满足所有人的要求,求安排的方案总数(这个数字可能很大,请输出方案总数取余989381的值,也可能为0)。
这问题背景真真真不煽情
啊。咳咳,走远了。
其实坐不坐在一起是无向的,我挨着你坐,那你肯定也挨着我坐。所以建一个无向森林,把所有要挨到一起的东西连上,然后发现这个森林里面的每一个联通块其实都应该是一条链。否则肯定无解。把所有链找出来之后打包,每一条链是有两种方法的顺这和倒着,若有a个人没有要求,一共有b条链那答案就是
那现在就来考虑怎么找链,好像可以直接用并查集维护。我比较沙茶,写的拓扑(虽然是无向图,但我建立的是双向有向边,拓扑每次考虑入度≤1的去搞)。
先考虑有两种情况是无解的,第一种就是链分叉了,第二种就是成环了。
第一种直接看如果连了A,B一条新边,看A,B的入度若≥3,那肯定就分叉了。直接0.
第二种就在拓扑中记录已经访问了多少点,若和有要求的人数不同,那么肯定就有环了。
然后这个水题就完了。
这种写法有个trick,就是如果A暗恋B,B暗恋A,这相当于有重边了,我每次都建立两个单向边,这下就建立了4个单向边,就搞成环了。
哎这么美妙的事情,为什么在程序中是个TRICK!哎,不是每件好事的发生对于人类的进展都是有益的。唉唉唉。。为什么我非要破坏了这美好一刻。
说点题外话:每个人都只会暗恋一个,所以只用开一个数组记一下,虽然我暴力map纯二啊!(这为什么是题外话。。)
最后:希望大家都有一个双向边,但一定不要出现多叉。
#include <cstdio>
#include <algorithm>
#include <map>
#define rep(i,l,r) for (int i=l;i<=r;++i)
typedef long long LL;
int getx(){
char c;int x;
for (c=getchar();c<'0'||c>'9';c=getchar());
for (x=0;c>='0'&&c<='9';c=getchar())
x=(x<<3)+(x<<1)+c-'0';
return x;
}
const LL MOD=989381;
const int MAX_N=500005;
int first[MAX_N],next[MAX_N<<1],to[MAX_N<<1];
int rd[MAX_N];
int tal=0;
void tjb(int x,int y){
next[++tal]=first[x];
first[x]=tal;
to[tal]=y;
rd[y]++;
}
int tot=0;
bool vis[MAX_N];
void topo(int v,int fa){
vis[v]=true;tot--;
for (int k=first[v];k;k=next[k]){
int u=to[k];
if (u==fa) continue;
if (--rd[u]<=1) topo(u,v);
}
}
LL power(LL a,LL b){
LL res=1;
for (;b;a=((LL)a*a)%MOD,b>>=1)
if (b&1) res=((LL)res*a)%MOD;
return res;
}
int n,m;
std::map<int,bool> edge[MAX_N];
bool choose[MAX_N];
int main(){
n=getx(),m=getx();
rep(i,1,m){
int x=getx(),y=getx();
if (x>y) x^=y,y^=x,x^=y;
if (!choose[x]){choose[x]=true;tot++;}
if (!choose[y]){choose[y]=true;tot++;}
if (!edge[x][y]){
tjb(x,y),tjb(y,x);
if (rd[x]>2||rd[y]>2) {printf("0");exit(0);}
edge[x][y]=true;
}
}
int s=n-tot;
int k=0;
rep(i,1,n)
if (!vis[i]&&rd[i]==1){k++;topo(i,0);}
if (tot>0){printf("0");exit(0);}
LL ans=1;
rep(i,1,s+k) ans=ans*i%MOD;
printf("%d\n",ans*power(2,k)%MOD);
}