zoukankan      html  css  js  c++  java
  • UVA-11174【Stand in a Line】

    题目大意:有一个村庄,里面有n个人,有些人的父亲也在这个村庄里。我们现在要将这些人排成一个队列,一个人不能排在他的父亲前面,问这种队列有多少种可能?

    解:很明显我们可以先建树。

    然后假设现在有这样一棵树:

    我们要如何统计父节点的方案数呢?

    首先我们先要确定每个子节点中的排列顺序,总共有6*8*2种,然后在其中一种的情况下,考虑怎么把它们穿插起来。

    如果我们把同一棵子树中的元素都看成相同元素,那么问题就变成了,现在有三种数(在样例中),它们的个数不同,问由它们组成的不同的排列有多少种?(全部的数都要用上)

    在这个样例中,每种数的个数分别是2,3,5.我们答案为x,那么可以得到一个等式2!*3!*5!*x=(2+3+5)!,这个可以自己想一下。所以我们就可以的得到答案。

    设当前子树的排法有f[i]种,子节点有s[i]个,则通过以上分析我们可得:

    f[i]=f[son1]*f[son2]*...*f[sonk]*(s[i]-1)/s[son1]!*s[son2]!*...*s[sonk]!(son1,son2...sonk是i的各个子节点)

    其实这样已经可以做了,不过我们还可以化简

    你会发现在最终的答案中,s[i]!会在分子中出现一次,(s[i]-1)!会在分母中出现一次(叶子结点不影响),所以把他们全部都约掉最终答案就成了:

    ans=(s[root]-1)!/s[1]!*s[2]!*s[3]!*...*s[n]!;

    所以只需深搜一遍,求出每棵子树的大小,然后预处理阶乘,并且因为模数是一个质数,所以根据小费马定理,用快速幂求出一个数的^(mo-2),即为这个数的逆。

    程序:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<vector>
    #define maxn 40009
    #define mo 1000000007
    using namespace std;
    typedef long long ll;
    int n,m,s[maxn],fa[maxn];
    vector<int>g[maxn];
    ll pow(ll now,int tot)
    {
      ll sum=1;
      while (tot)
      {
          if (tot&1) sum=(sum*now)%mo;
          now=(now*now)%mo;
          tot=tot>>1;
      }
      return sum;
    }
    void dfs(int x)
    {
      s[x]=1;
      for (int i=0;i<g[x].size();i++)
      dfs(g[x][i]),s[x]+=s[g[x][i]];
    }
    int main()
    {
      int t;
      scanf("%d",&t);
      while (t--)
      {
       scanf("%d%d",&n,&m);
       for (int i=0;i<=n;i++)
       {
        while (g[i].size()) g[i].pop_back();
        fa[i]=0;
       }
       int x,y;
       for (int i=1;i<=m;i++)
       {
           scanf("%d%d",&x,&y);
           fa[x]=y;
       }
       for (int i=1;i<=n;i++) g[fa[i]].push_back(i);
       dfs(0); ll ans=1;
       for (int i=2;i<=n;i++) ans=(ans*i)%mo;
       for (int i=1;i<=n;i++)
       ans=(ans*pow(s[i],mo-2))%mo;
       printf("%lld
    ",ans);
      }
      return 0;
    }
  • 相关阅读:
    最短路小变形
    最短路
    bfs + 路径输出
    优先队列
    dijkstra
    重载运算符-operator
    最短路
    二分图匹配
    依赖型的关系建立
    string 类
  • 原文地址:https://www.cnblogs.com/2014nhc/p/8184561.html
Copyright © 2011-2022 走看看