目录

20190809 refrain——博士之时

20190809 refrain——博士之时

思路:

由于一个点最多有两个度,所以这张图只会存在链和长度为偶数的环和孤点

考虑计算合法方案

考虑每个环和链对答案的贡献:

  1. 对于一个长度为$2n$ 的环,可以发现当环进行$2i(1\le i \le n)$次旋转时,旋转后的环跟原来的环一模一样,是合法的。所以共有$n$种合法方案

  2. 对于一个长度为偶数的链,可以发现只有1种合法方案(即原图)

  3. 对于一个长度为奇数的链,可以发现有两种合法方案(即原图和整个反转)

  4. 对于一个孤点,只有一种方案

最后,若有$k$个完全一样的图,显然可以互相交换,共有$k!$种方案,而这些图各自又能变换,设这种图有$c$种合法方案,则总方案数为$c^k∗k!$ 最后,只要把总方案数减去合法方案数即是最后答案

代码:

100分做法

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int P = 1e9 + 7;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y)
{
    x = max(x, y);
}
template <typename T> void chkmin(T &x, T y)
{
    x = min(x, y);
}
template <typename T> void read(T &x)
{
    x = 0;
    int f = 1;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
    x *= f;
}
template <typename T> void write(T x)
{
    if (x < 0) x = -x, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
template <typename T> void writeln(T x)
{
    write(x);
    puts("");
}
bool vis[MAXN];
map <pair <int, int>, int> mp;
vector <pair <int, bool>> a[MAXN];
void work(int pos, int fa, bool fc, int cnta, int cntb)
{
    if (vis[pos])
    {
        mp[make_pair(-cnta, -cntb)]++;//环的情况

        return;
    }
    vis[pos] = true;
    for (auto x : a[pos])//对于所有出边

        if (x != make_pair(fa, fc))//不是入边的话

        {
            work(x.first, pos, x.second, cnta + x.second, cntb + !x.second);
            return;
        }
    mp[make_pair(cnta, cntb)]++;//记录

}
int power(int x, int y)
{
    if (y == 0) return 1;
    int tmp = power(x, y / 2);
    if (y % 2 == 0) return 1ll * tmp * tmp % P;
    else return 1ll * tmp * tmp % P * x % P;
}
int main()
{
    freopen("refrain.in", "r", stdin);
    freopen("refrain.out", "w", stdout);
    int num;
    read(num);
    int n, na, nb;
    read(n), read(na), read(nb);
    for (int i = 1; i <= na; i++)
    {
        int x, y;
        read(x), read(y);
        a[x].emplace_back(y, true);
        a[y].emplace_back(x, true);
    }
    for (int i = 1; i <= nb; i++)
    {
        int x, y;
        read(x), read(y);
        a[x].emplace_back(y, false);
        a[y].emplace_back(x, false);
    }
    for (int i = 1; i <= n; i++)
        if (!vis[i] && a[i].size() <= 1) work(i, 0, 0, 0, 0);//链或孤点的情况

    for (int i = 1; i <= n; i++)
        if (!vis[i]) work(i, 0, 0, 0, 0);//环的情况

    int ans = 1;
    for (auto x : mp)
    {
        pair <int, int> tmp = x.first;
        for (int i = 1; i <= x.second; i++)
            ans = 1ll * ans * i % P;
        if (tmp.first < 0) ans = 1ll * power(2ll * -tmp.first % P, x.second) * ans % P;
        else if (tmp.first != tmp.second) ans = 1ll * power(2ll, x.second) * ans % P;
    }
    int finalans = 1;
    for (int i = 1; i <= n; i++)
        finalans = 1ll * finalans * i % P;
    writeln((finalans - ans + P) % P);
    return 0;
}