Uva 11174 Stand in a Line 解题报告(递推+逆元)


    解题报告:刘汝佳老师书中的题目。不得不承认,推理的十分精妙。逆元,遍历树什么的都不是难点,难点在于这推出来的公式。

    代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int mod = 1000000007;
typedef long long LL;

int powMod(LL a, int b)
{
    LL res = 1;
    while(b)
    {
        if(b&1)
            res = res*a%mod;
        b>>=1;
        a = a*a%mod;
    }
    return (int)res;
}

int inv(int n)
{
    return powMod(n, mod-2);
}

const int maxn = 40010;
int first[maxn],nxt[maxn],vv[maxn];
bool isSon[maxn];
int factorial[maxn];
LL ans;

void init()
{
    factorial[0] = 1;
    for(int i=1;i<maxn;i++)
        factorial[i] = (long long)factorial[i-1]*i%mod;
}

int dfsTree(int n,int p=0)
{
    int sonNum=1;
    for(int e=first[n];e;e=nxt[e])
        sonNum+=dfsTree(vv[e],n);

    if(sonNum>1) ans = ans*inv(sonNum)%mod;
    return sonNum;
}

void work()
{
    int n,m;
    scanf("%d%d",&n,&m);
    ans = factorial[n];

    int e = 2;
    memset(first, 0, sizeof(first));
    memset(isSon, 0, sizeof(isSon));
    while(m--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        nxt[e] = first[v], vv[e] = u, first[v] = e++;
        isSon[u] = true;
    }

    for(int i=1;i<=n;i++) if(!isSon[i])
        dfsTree(i);

    printf("%d\n", (int)ans);
}

int main()
{
    init();

    int T;
    scanf("%d", &T);
    while(T--)
        work();
}


你可能感兴趣的:(递推)