首页 > 代码库 > uva 11174 - Stand in a Line(逆元+递推)

uva 11174 - Stand in a Line(逆元+递推)

题目连接:uva 11174 - Stand in a Line

题目大意:村子里有n个村名民,现在他们要排成一列,处于对长辈的尊敬,他们不能排在自己父亲的前面,有些人的父亲不一定在村子了。问有多少种列的顺序。

解题思路:【算法竞赛入门经典-训练指南】的例题,主要还用到了欧几里得拓展定理求逆元。

#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
typedef long long ll;
const int N = 40005;
const ll MOD = 1e9+7;

int n, m;
ll v[N];
vector<int> g[N];

void init () {
    scanf("%d%d", &n, &m);

    memset(v, 0, sizeof(v));
    for (int i = 0; i <= n; i++)
        g[i].clear();

    int a, b;
    for (int i = 0; i < m; i++) {
        scanf("%d%d", &a, &b);
        g[b].push_back(a);
    }
}

ll dfs(int x) {
    if (v[x])
        return v[x];

    for (int i = 0; i < g[x].size(); i++)
        v[x] += dfs(g[x][i]);
    return ++v[x];
}

void gcd (ll a, ll b, ll& x, ll& y, ll& d) {
    if (b == 0) {
        d = a;
        x = 1;
        y = 0;
    } else {
        gcd(b, a%b, y, x, d);
        y -= x*(a/b);
    }
}

int main () {
    int cas;
    scanf("%d", &cas);
    while (cas--) {
        init ();

        ll ans = 1, b = 1;
        for (ll i = 1; i <= n; i++)
            ans = (ans * i) % MOD;

        for (int i = 1; i <= n; i++)
            b = (b * dfs(i)) % MOD;

        ll p, k, d = 1;
        gcd(b, MOD, p, k, d);
        ans = ((ans * p) % MOD + MOD) % MOD;
        printf("%lld\n", ans);
    }
    return 0;
}