noip模拟赛 少女

时间:2022-12-17 12:53:22

noip模拟赛 少女

分析:每个连通块都是独立的,对一个连通块进行分析.如果边数>点数,显然是不可能的,因为每条边要分配给一个点,至少有一个点分配了两次以上.如果边数=点数,就形成了环,有两种方案,顺时针一个环,逆时针一个环.如果边数=点数-1,形成了链,将n个点分配n-1条边,答案为C(n,n-1),也就是n,统计一下每个连通块有多少个点,多少条边就可以了.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 200010, mod = 1e9 + 7;

int n, m, cnt1, cnt2, head[maxn], to[maxn], nextt[maxn], tot = 1;
bool vis[maxn], vis2[maxn];
long long ans = 0;

void add(int x, int y)
{
    to[tot] = y;
    nextt[tot] = head[x];
    head[x] = tot++;
}

void dfs(int u)
{
    vis[u] = 1;
    cnt1++;
    for (int i = head[u]; i; i = nextt[i])
    {
        int t = i, t2;
        if (t % 2 == 0)
            t2 = i - 1;
        else
            t2 = i + 1;
        if (!vis2[i])
        {
            cnt2++;
            vis2[t] = vis2[t2] = 1;
        }
        int v = to[i];
        if (!vis[v])
            dfs(v);
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
        add(v, u);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            cnt1 = 0;
            cnt2 = 0;
            dfs(i);
            if (cnt1 == cnt2)
            {
                if (ans == 0)
                    ans = 2;
                else
                    ans = (ans * 2) % mod;
            }
            if (cnt1 == cnt2 + 1)
            {
                if (ans == 0)
                    ans = cnt1;
                else
                    ans = (ans * cnt1) % mod;
            }
        }
    }
    printf("%lld\n", ans);

    return 0;
}