• UVA11174村民排队问题


    题意:
         有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 " ,Ans);
       }
       return 0;
    }
          
          
          
       
          

















  • 相关阅读:
    Peewee中join三张及以上的表时只能获取一张表的数据
    Ubuntu18.04安装 NVIDIA显卡驱动+CUDA+cuDNN+Pytorch
    Kubernetes Deployment 并行重启Pod
    git config 配置用户名、邮箱
    Python __str__() 方法
    阅读-自律100天-SMART法则
    Jenkins 调用执行jmeter脚本,并直接生成html报告
    推荐一款开源的Diffy自动化测试框架(转)
    mysql binlog日志自动清理及手动删除
    大数据测试
  • 原文地址:https://www.cnblogs.com/csnd/p/12062570.html
Copyright © 2020-2023  润新知