题目:
n个人排成一排,有m个条件,第i个条件要求ai和bi相邻,求方案数。
【数据范围】
100%的数据,0<n≤500000,1≤Ai,Bi≤n,0≤m≤n,保证没有人自恋。
算法:并查集+组合数
难度:NOIP
题解:
由于要求排成一排,因此如果关系出现了环则无解;而一个位置最多挨着两个,所以deg[x]>3也无解。
那么剩下的就是若干条链和单个点。每一条链的排列方式有两种,而单个点的排列方式只有一种。
方案数=
时间复杂度:
代码如下:
注意重边的问题(a->b,b->a)。由于保证了ai互不相同,因此可以对每一个ai存一个bi,
每次只有在bi的暗恋对象不为ai时才更新。
#include <bits/stdc++.h>
#define ll long long
#define N 500005
using namespace std;
const ll mod=989381;
int fa[N];
int findf(int x)
{
if(x==fa[x]) return x;
return fa[x]=findf(fa[x]);
}
int w[N],deg[N];
int cnt[N];
/*ll powermod(int x,int y)
{
ll ret=1;
x=x%mod;
while(y)
{
if(y%2)
{
ret=(ret*x)%mod;
}
y=y/2;
x=(x*x)%mod;
}
return ret%mod;
}*/
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
fa[i]=i;
}
for(int i = 1;i <= m;i++)
{
int a;
scanf("%d",&a);//必须换行读入
scanf("%d",&w[a]);
if(w[w[a]]==a) continue;
int t1=findf(a);
int t2=findf(w[a]);
if(t1==t2||deg[a]>=2||deg[w[a]]>=2)
{
puts("0");
exit(0);
}
fa[t1]=t2;
deg[a]++,deg[w[a]]++;
}
for(int i = 1;i <= n;i++) cnt[findf(i)]++;
ll ans=1;
int ct=0;
int cn=0;
for(int i = 1;i <= n;i++)
{
if(cnt[i])
{
if(cnt[i]>=2) cn++;
else ct++;
}
}
for(int i = 1;i <= cn+ct;i++)
{
ans=((ans%mod)*(i%mod))%mod;
}
ll anss=1;
for(int i = 1;i <= cn;i++)
{
anss=((anss%mod)*(2%mod))%mod;//此题用快速幂会爆炸!!!
}
ans=((ans%mod)*(anss%mod))%mod;
printf("%lld\n",ans%mod);
return 0 ;
}