codeforces859E Desk Disorder 并查集判环+乘法原理

题目链接:戳这里

题目大意:有N 个人和2N 个座位。告诉你这N 个人它们现在的座位。以及它们想去的座位。 每个人可以去它们想去的座位或者就坐在原来的座位上。 新的座位安排和旧的座位安排,都不允许一个座位被两个人占据的情况。 问你新的座位安排的方案数。

题解:可以发现不同的联通块是互不影响的,那么我们就可以统计出所有联通块分开统计答案在按照乘法原理乘起来。

如果一个联通块内存在自环,那么答案为0。

如果一个联通块是一个环,那么答案为2(不动或者每个人都换)

否则答案就是联通块内的节点个数。

找联通块和判环可以用并查集解决。

代码:

#include<bits/stdc++.h>
#define maxn 200005
#define mod 1000000007
using namespace std;
typedef long long LL;
int read()
{
    char c;int sum=0,f=1;c=getchar();
    while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
    return sum*f;
}
int n,x,y;
int fa[maxn],size[maxn],can[maxn],huan[maxn];
LL ans=1;
void init()
{
    for(int i=0;i<=2*n;i++)
    fa[i]=i,size[i]=1;
}
int getfa(int x)
{
    return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
int main()
{
    n=read();
    init();
    for(int i=1;i<=n;i++)
    {  
        x=read();y=read();
        if(x==y) can[getfa(x)]=1;
        int u=getfa(x),v=getfa(y);
        if(u!=v)
        {
            fa[u]=v;
            size[v]+=size[u];
            can[v]|=can[u];
        }
        else huan[u]=1;
    }
    for(int i=1;i<=2*n;i++)
    if(getfa(i)==i)
    {
        if(can[i]) continue;
        if(huan[i]) ans=ans*2%mod;
        else ans=ans*(LL)size[i]%mod;
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_39791208/article/details/79384206