zoukankan      html  css  js  c++  java
  • 【bzoj3444】最后的晚餐 并查集

    题目描述

    n个人排成一排,有m个条件,第i个条件要求ai和bi相邻,求方案数。

    输入

    输入有m+1行,第一行有两个用空格隔开的正整数n、m,如题所示。接下来的m行,每一行有两个用空格隔开的正整数,第i行为Ai和Bi,表示Ai的暗恋对象为Bi,保证Ai互不相等。

    输出

    输出只有一行,这一行只有一个数字,如题所示。

    样例输入

    4 2
    1 2
    4 3

    样例输出

    8


    题解

    并查集

    由于排成一排,因此如果关系出现了环则无解;而一个位置最多挨着两个,所以一个点的度数大于3也无解。

    那么剩下的就是若干条链和单个点。链的排列方式有两种,而单个点的排列方式只有一种。

    然后再乘上把它们放到一起的全排列即为答案。

    可以使用并查集来维护连通性、判环。

    注意重边的问题(a->b,b->a)。由于保证了ai互不相同,因此可以对每一个ai存一个bi,每次只有在bi的暗恋对象不为ai时才更新。

    时间复杂度$O(n·alpha(n))$

    #include <cstdio>
    #include <algorithm>
    #define N 500010
    #define mod 989381
    using namespace std;
    int a[N] , f[N] , d[N] , cnt[N] , tot;
    int find(int x)
    {
    	return x == f[x] ? x : f[x] = find(f[x]);
    }
    int main()
    {
    	int n , m , i , x;
    	long long ans = 1;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ ) f[i] = i;
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d" , &x);
    		scanf("%d" , &a[x]);
    		if(a[a[x]] == x) continue;
    		if(find(x) == find(a[x]) || d[x] >= 2 || d[a[x]] >= 2)
    		{
    			puts("0");
    			return 0;
    		}
    		d[x] ++ , d[a[x]] ++ , f[f[x]] = f[a[x]];
    	}
    	for(i = 1 ; i <= n ; i ++ ) cnt[find(i)] ++ ;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		if(cnt[i])
    		{
    			if(cnt[i] > 1) ans = ans * 2 % mod;
    			tot ++ ;
    		}
    	}
    	while(tot) ans = ans * tot % mod , tot -- ;
    	printf("%lld
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    java入门学习(二)
    java入门学习(一)
    python3之数据类型
    pip基础用法
    python中的序列化与反序列化
    python装饰器
    python WEB接口自动化测试之requests库详解
    QQ发送邮件实例
    获取当前目录下最新的文件
    The Zen of Python
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7603675.html
Copyright © 2011-2022 走看看