您的位置:首页 > 其它

ACM: uva 11174 - Stand in a Line

2016-05-19 23:29 387 查看
Stand in a Line
 
All the people in
the byteland want to stand in a
line in such a way that no person stands closer to the front of the
line than his father. You are given the information about the
people of
the byteland.  You
have to determine the number of ways
thebytelandian people can stand in a line.

 
Input
First line of the input contains T (T<14) the
number of test case. Then following lines contains T Test
cases.

Each test case starts with 2 integers n (1≤n≤40000) and m
(0≤m

 

 
Output
For each test case the output contains a single line denoting
the number of different ways the soldier can stand in a single
line. The result may be too big. So always output the remainder on
dividing ther the result by 1000000007.

 

 

Sample Input 

3

3 2

2 1

3 1

3 0

3 1

2 1

 

Output for Sample Input

2

6

3

 

题意: 村民排队, 有n个人要求排成一列, 但是要求每个人不能排在他的父亲前面, 计算出有多少种排列方式.

     
其中有些人得父亲不在里面. 最后结果对1 000 000 007求余

 

解题思路: (一道好题!)

    1.
森林问题, 只需要添加一个虚拟公共祖先就可以变成树了, 添加一个0虚拟公共祖先. 其余1~n编号

       设:
f[i]表示以i为根的子树排列数量, 每个节点数为s[i];

    2.
现在以C为子树根的子树, ci为其孩子, 先考虑每课以孩子节点为根的子树的排列是相互独立的,

       满足乘法原理,
所以不考虑子树之间的排列时排列总数为: f[c1]*f[c2]*f[c3]*...*f[ck];(k个孩子)

       在把每棵子树中的全部节点看成相同的元素,
相当于有重复元素的全排列种数: n!/(n1!*n2!*...nk!)

      
即: f[C] = f[c1]*f[c2]*...*f[ck]*(s[C]-1)! /
(s[c1]!*s[c2]!*...*s[ck]!);

      
将递归式化简得: f[root] = (s[root]-1)! /
(s[1]*s[2]*...*s
);

    3.
剩下的问题是如何快速求出表达式结果, f[root] % MOD的值, MOD是一个素数, 一个数除以x, 相当于

      
乘以x的逆.(群概念中的逆);

 

代码:

#include <cstdio>

#include <iostream>

#include <cstring>

using namespace std;

#define MAX 40005

#define MOD 1000000007

typedef long long ll;

struct node

{

 int v;

 int next;

}edges[MAX*2];

int n, m;

int first[MAX], num;

bool flag[MAX];

ll fac[MAX], inv[MAX];

ll ans;

void exgcd(ll a, ll b, ll &x, ll
&y, ll &d)

{

 if( b == 0 )

 {

  d = a;

  x = 1;

  y = 0;

 }

 else

 {

  exgcd(b, a%b, y, x, d);

  y -= x*(a/b);

 }

}

ll inverse(ll a, ll M)

{

 ll x, y, d;

 exgcd(a, M, x, y, d);

 return d == 1 ? (x+M)%M : -1;

}

void init()

{

 fac[0] = 1;

 for(int i = 1; i <= 40000;
++i)

 {

  fac[i] = fac[i-1]*i %
MOD;

  inv[i] = inverse(i, MOD);

 }

}

void add(int u, int v)

{

 edges[num].v = v;

 edges[num].next = first[u];

 first[u] = num++;

}

int dfs(int u)

{

 int cur = 1;

 for(int e = first[u]; e != -1; e =
edges[e].next)

  cur += dfs(edges[e].v);

 if(u != 0)

  ans = ans * inv[cur] %
MOD;

 return cur;

}

int main()

{

// freopen("input.txt", "r", stdin);

 init();

 int caseNum, i;

 scanf("%d", &caseNum);

 while(caseNum--)

 {

  scanf("%d %d",
&n, &m);

  num = 1;

  memset(first, -1,
sizeof(first));

  memset(flag, false,
sizeof(flag));

  int u, v;

  for(i = 1; i <=
m; ++i)

  {

   scanf("%d
%d", &u, &v);

   add(v,
u);

   flag[u] =
true;

  }

  for(i = 1; i
<= n; ++i)

   if( !flag[i]
) add(0, i);

  ans = fac
;

  dfs(0);

  printf("%lld\n", ans);

 }

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: