URAL 1962 In Chinese Restaurant 并查集

来源:互联网 发布:cisco 配置多个端口 编辑:程序博客网 时间:2024/05/19 20:00

D - 忠厚人
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit Status Practice URAL 1962

Description

When Vova arrived in Guangzhou, his Chinese friends immediately invited him to a restaurant. Overall n people came to the restaurant, including Vova. The waiter offered to seat the whole company at a traditional large round table with a rotating dish plate in the center.
As Vova was a guest, he got the honorable place by the door. Then m people in the company stated that they wanted to sit near a certain person. Your task is to determine the number of available arrangements to seat Vova's friends at the table.

Input

The first line contains integers n and m (2 ≤ n ≤ 100; 0 ≤ m ≤ n). The next m lines contain integers k1, …, km, where ki is the number of the person who the person number i wants to sit with (1 ≤ ki ≤ nki ≠ i). Being an honorable guest, Vova got number 1. His friends are numbered with integers from 2 to n.

Output

Print the number of available arrangements to seat Vova's friends modulo 10 9 + 7.

Sample Input

inputoutput
6 6211565
4
4 3231
0

Source

UESTC 2016 Summer Training #14 Div.2

URAL 1962


My Solution

并查集

以前好像做过类似的题

首先如果一个节点有sz[i] > 2 则 ans = 0

如果有环, 而且不是最大的环, 则ans = 0

如果是最大的环, 则ans = 2  //! 最开始误认为是1, 白白WA了2发, 然后才明白 顺时针和逆时针2种方案


剩下的就是常规的ans了

先是求树的全排列, // 更像是圆排列 A(n, n) / n  或者说把1的位置固定然后求全排列

然后对于每个树:

1)只要节点数大于1, 都会有2头无论是不是直链, 都和直链一样

因为如果有2个分支, 那么那两个分支自己必须是直链(否则 ans = 0), 两个直链拼到root上, 拉直就是直链

所以这个时候每个树 ans*2

1)如果该树只有一个节点, 则只有一种情况了

复杂度 O(n)


#include <iostream>#include <cstdio>#include <map>#include <cstring>using namespace std;typedef long long LL;const int maxn = 1e6 + 8;map<int, map<int, int> > cnt;int father[maxn], _rank[maxn], sz[maxn], trees[maxn];bool flag;inline void DisjointSet(int n){    for(int i = 0; i <= n; i++){        father[i] = i;        trees[i] = 1;    }}int _find(int v){    return father[v] == v ? v : _find(father[v]);}void _merge(int x, int y){    int a = _find(x), b = _find(y);    if(a == -1 || b == -1) return;                //    if(_rank[a] < _rank[b]){        father[a] = b;        trees[b]++;    }    else{        father[b] = a;        trees[a]++;        if(_rank[a] == _rank[b]){            _rank[a]++;        }    }}const LL Hash = 1e9 + 7;inline LL mod(LL x){    return x - x/Hash*Hash;}int main(){    #ifdef LOCAL    freopen("a.txt", "r", stdin);    //freopen("b.txt", "w", stdout);    int T = 3;    while(T--){    #endif // LOCAL    memset(sz, 0, sizeof sz);    int n, m, val, sum;    LL ans = 1;    flag = true;    scanf("%d%d", &n, &m);    sum = n;    DisjointSet(n);    for(int i = 1; i <= m; i++){        scanf("%d", &val);        if(cnt[i][val] || cnt[val][i]) continue;        sz[i]++; cnt[i][val]++;        sz[val]++; cnt[val][i]++;        if(sz[i] > 2 || sz[val] > 2) flag = false;        //if(flag){            if(_find(val) != _find(i)){                trees[_find(i)] += trees[_find(val)];                father[_find(val)] = father[_find(i)];                sum--;            }            else flag = false;        //}    }    if(n == 2) {printf("1"); return 0;}    for(int i = 1; i <= n; i++){        if(sz[i] > 2) {printf("0"); return 0;}    }    if(!flag) {if(sum > 1)printf("0"); else printf("2");}  //!大环是2 不是 1 (┬_┬)    else{        //cout<<"sum"<<sum<<endl;        for(int i = 1; i < sum; i++)            ans = mod(ans*i);        //cout<<ans<<endl;        for(int i = 1; i <= n; i++){            if(father[i] == i){                if(trees[i] > 1) {ans = mod(ans*2);}            }        }        printf("%I64d", ans);    }    #ifdef LOCAL    cnt.clear();    printf("\n");    }    #endif // LOCAL    return 0;}

  Thank you!

                                                                                                                                               ------from ProLights

0 0
原创粉丝点击