链接:http://acm.timus.ru/problem.aspx?space=1&num=1962
题意:N个人坐大圆桌,1必须坐在1号位置,前M个人要求坐Ki的身边,问有几种安排位置的方式。
题解:其实因为N范围比较小,所以用DFS解是挺快的。但是表示我又脑洞大开写了一个并查集。。
基本思路是将相接触的数字放到一个集合。如果出现环,要判定环是否合法。
搞完出来的结果就是,若干个集合。。其中有1的集合位置确定,剩下的集合可以排列组合,总共N!种。然后对于所有集合,如果一个集合个数大于2,可以调换前后位置,也就是还要*2。
最后注意N=2的情况。。不管怎么都输出1,坑死我了。。
总之就是很多特判的题目,代码奉上:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
#define LL __int64
#define MOD 1000000007
int n,m,fa[100100];
int hash[100100];
int getfa(int x)
{
if (fa[x]!=x) return fa[x]=getfa(fa[x]);
else return x;
}
void add(int x,int y)
{
if (x>y) fa[x]=y;
else fa[y]=x;
}
bool check()
{
for (int a=1;a<=n;a++)
if (getfa(a)!=1) return false;
return true;
}
int MAP[110][110];
int main()
{
int a,b;
int P;
while(~scanf("%d%d",&n,&m))
{
if (n==2)
{
for (a=1;a<=m;a++) scanf("%d",&P);
printf("1\n");continue;
}
for (a=1;a<=n;a++)
{
fa[a]=a;
hash[a]=2;
}
memset(MAP,0,sizeof(MAP));
bool flag=true;
for (a=1;a<=m;a++)
{
scanf("%d",&P);
int X=getfa(a);
int Y=getfa(P);
if (MAP[a][P]==1) continue;
else
{
MAP[a][P]=1;
MAP[P][a]=1;
}
if (X==Y)
{
if (hash[a]==1&&hash[P]==1&&check())
{
continue;
}
else
{
printf("0\n");
flag=false;
break;
}
}
else
{
add(X,Y);
hash[a]--;
hash[P]--;
if (hash[a]<0||hash[P]<0)
{
printf("0\n");
flag=false;
break;
}
}
}
for (a++;a<=m;a++) scanf("%d",&P);
if (!flag) continue;
map <int,int> M;
M.clear();
for (a=1;a<=n;a++)
{
int X=getfa(a);
if (M.find(X)!=M.end()) {M[X]+=1;}
else M[X]=1;
}
LL whole=1;
int num=0;
map <int,int>::iterator it;
for (it=M.begin();it!=M.end();it++)
{
//cout<<(*it).first<<' '<<(*it).second<<endl;
if ((*it).first==1)
{
if ((*it).second>1) whole=(whole*2)%MOD;
else whole=whole;
}
else
if ((*it).second>1) {num++;whole=(whole*2*num)%MOD;}
else {num++;whole=(whole*num)%MOD;}
}
printf("%I64d\n",whole);
}
return 0;
}