题意:

     有n个人要排队,给你一些父子关系,要求儿子不能站在自己的父亲前面,问有多少种排队方式?

思路:

      白书上的题目,首先我们可以把关系建成树,这样我们就有可能得到一个森林(或者是一课树),然后我们再虚拟出来一个点0连接所有森林的根节点,这样是为了保证是一棵树,然后题目就变成了给你一棵树,不改变关系,问这个树有多少种方式,这个还是排列组合问题,对于每一个根节点,有这样的性质

root[i] = f[1]*f[2]*..f[k]   *  (s[i]-1)!/s[1]!*s[2]!*..s[k]! 

f[1]..f[k]表示的当前根节点连接的k个儿子为根节点的树的排列个数,s[i]表示的是以i为根节点的这棵树的所有节点个数,上面的式子可以理解成这样

f[1]*f[2]*..f[k] 所有儿子为根节点的排列个数

(s[i] - 1)! 表示的是以i为根的这棵树的所有节点数-1(不算跟所以-1)的排列方式

//s[1]!*s[2]!*..s[k]!  相当于全排列去掉重复部分,因为每一棵树已经*f[]了,不能在*了,不能再*那就可以理解成重复部分了,所以...,然后把每一个公式都化简,会发现分子剩1,分母剩s[i]了,(可以理解成分子的f[i]和分母的s[i]!约),这样最后剩下的是

((n+1)-1)/s1*s2*..sn;

最后的公式是

Ans = n!/(s1*s2*s3*s4...*sn) si是以i为根节点的子树的节点数

这样就可以了,然后这样会设计到一个问题,那就是大数相除取余的问题,我知道应该有至少两种方法解决这个问题,一个是逆元,另一个是a/b%c = a * pow(b ,c - 2) % c,这个不解释了,可以自己去网上找学习,哎!想起了亚洲赛那道排列组合题,当时在赛场上怎么也想不起来大数相除的转换了,sb了!

#include<stdio.h>

#include<string.h>

#define MOD 1000000007

#define N_node 40000 + 10

#define N_edge 40000 + 10

typedef struct

{

   int to ,next;

}STAR;

STAR E[N_node];

long long sum[N_node];

long long jc[N_node];

int list[N_node] ,tot;

int du[N_node];

void add(int a ,int b)

{

   E[++tot].to = b;

   E[tot].next = list[a];

   list[a] = tot;

}

int DFS(int now)

{

   int s = 1;

   for(int k = list[now] ;k ;k = E[k].next)

   {

      s += DFS(E[k].to);

   }

   sum[now] = s;

   return s;

}

long long Pow(long long a ,long long b)

{

   long long c = 1;

   while(b)

   {

      if(b & 1) c *= a;

      b >>= 1;

      a *= a;

      a = a % MOD;

      c = c % MOD;

   }

   return c;

}

void DB()

{

   long long now = 1;

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

   {

      now = now * i % MOD;

      jc[i] = now;

   }

}

   

int main ()

{

   int n ,m ,i ,a ,b ,t;

   DB();

   scanf("%d" ,&t);

   while(t--)

   {

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

      memset(list ,0 ,sizeof(list)) ,tot = 1;

      memset(du ,0 ,sizeof(du));

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

      {

         scanf("%d %d" ,&a ,&b);

         add(b ,a);

         du[a] ++;

      }

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

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

      memset(sum ,0 ,sizeof(sum));

      DFS(0);

      long long Ans = jc[n];

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

      {

          Ans = Ans * Pow(sum[i] ,MOD - 2) % MOD;

      }

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

   }

   return 0;

}

      

      

      

   

      

UVA11174村民排队问题的更多相关文章

  1. [uva11174]村民排队 递推+组合数+线性求逆元

    n(n<=40000)个村民排成一列,每个人不能排在自己父亲的前面,有些人的父亲不一定在.问有多少种方案. 父子关系组成一个森林,加一个虚拟根rt,转化成一棵树. 假设f[i]表示以i为根的子树 ...

  2. acdream 1683 村民的怪癖(KMP,经典变形)

    Problem Description 娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近.忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之 ...

  3. POJ 2828 Buy Tickets(排队问题,线段树应用)

    POJ 2828 Buy Tickets(排队问题,线段树应用) ACM 题目地址:POJ 2828 Buy Tickets 题意:  排队买票时候插队.  给出一些数对,分别代表某个人的想要插入的位 ...

  4. D - 娜娜梦游仙境系列——村民的怪癖

    D - 娜娜梦游仙境系列——村民的怪癖 Time Limit: 2000/1000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Othe ...

  5. Python开发——排队问题随机模拟分析

    案例:主要是基于"蒙特卡罗思想",求解排队等待时间问题 场景:厕所排队问题 1.两场电影结束时间相隔较长,互不影响: 2.每场电影结束之后会有20个人想上厕所: 3.这20个人会在 ...

  6. 银行排队问题之单队列多窗口加VIP服务(30 分)

    银行排队问题之单队列多窗口加VIP服务(30 分) 假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙.当有窗口空闲时,下一位顾客即去该窗口处理事务.当有多个窗口可选 ...

  7. PTA 银行排队问题之单队列多窗口服务(25 分)

    银行排队问题之单队列多窗口服务(25 分) 假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙.当有窗口空闲时,下一位顾客即去该窗口处理事务.当有多个窗口可选择时,假 ...

  8. POJ2182(排队问题)

    Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10695   Accepted: 6865 Descri ...

  9. codevs——2956 排队问题

    2956 排队问题  时间限制: 1 s  空间限制: 32000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description 有N个学生去食堂,可教官规定:必须2人或3 ...

随机推荐

  1. Github Fork与远程主分支同步

    fork与主分支同步(5步) 1. git remote add upstream git@github.com:haichong98/gistandard.git   新建一个upstream的远程 ...

  2. 零投资!零风险!手把手教你挖pi币

    为什么说PI币属于区块链4.0代币呢?我们先从人类社会的生产力生产关系的递进来做一波有利的证明! 原始社会--封建王朝--君主立宪--资本主义--社会主义 原始社会:社会物质财富分配既有弱肉强食也有按 ...

  3. MyBatis(十一):MyBatis架构流程浅析

    架构分层 我们将MyBatis架构分为三层,分别为接口层.数据处理层和框架支撑层 接口层:提供外部接口调用的API,使用端通过这些API来操作数据库,接口层收到请求后会调用数据处理层完成具体的数据处理 ...

  4. js 算数组平均值、最大值、最小值、偏差、标准差、中位数、数组从小打大排序、上四分位数、下四分位数

    要算的数组命名为data var sum = function(x,y){ return x+y;}; //求和函数 var square = function(x){ return x*x;}; / ...

  5. python创建一个二维列表

    方法一:利用for-in语句来生成一个二维列表 a = [] 2 for i in range(10): 3 a.append([]) 4 for j in range(10): 5 a[i].app ...

  6. 01-静态web服务器(Python)-面向对象的对比

    普通写法,静态web服务器: 先创建TCP服务器套接字,然后等待客户端(这里是浏览器)请求连接. 客户端发起请求,用线程来处理连接的建立,这样可以实现多任务(也就是并发) 连接后根据请求发送指定页面 ...

  7. Cup HDU - 2289

    题目传送门:https://vjudge.net/problem/HDU-2289 题意:有一个上口小于底部的圆台形水杯,告诉我们水的体积求水高度. 思路:利用高中数学知识求rr然后二分求h,具体化简 ...

  8. ch1_6_6求解门禁系统问题

    import java.util.HashMap; import java.util.Scanner; public class ch1_6_6求解门禁系统问题 { public static voi ...

  9. TEB 、TIB、PEB--Vista 32

    TEB struct TEB typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVO ...

  10. SynchronousQueue核心源码分析

    一.SynchronousQueue的介绍 SynchronousQueue是一个不存储元素的阻塞队列.每一个put操作必须等待一个take操作,否则不能继续添加元素.SynchronousQueue ...