题意:

有n个人排队,要求每个人不能排在自己父亲的前面(如果有的话),求所有的排队方案数模1e9+7的值。

分析:

《训练指南》上分析得挺清楚的,把公式贴一下吧:

设f(i)为以i为根节点的子树的排列方法,s(i)表示以i为根的子树的节点总数。

f(i) = f(c1)f(c2)...f(ck)×(s(i)-1)!/(s(c1)!s(c2)!...s(ck)!)

按照书上最开始举的例子,其实这个式子也不难理解,就是先给这些子树确定一下位置,即有重元素的全排列。

子树的位置确定好以后,然后再确定子树中各个节点的顺序。

对了,因为求组合数会用到除法,而且1e9+7又是个素数,所以我们在做除法的时候只要乘上它对应的乘法逆元即可。

这是递归计算的代码:

 #include <bits/stdc++.h>

 using namespace std;

 const int maxn =  + ;
const int MOD = ; vector<int> sons[maxn];
int fa[maxn], fac[maxn], ifac[maxn]; inline int mul_mod(int a, int b, int n = MOD)
{
a %= n; b %= n;
return (int)((long long)a * b % n);
} void gcd(int a, int b, int& d, int& x, int& y)
{
if(!b) { d = a; x = ; y = ; }
else{ gcd(b, a%b, d, y, x); y -= x*(a/b); }
} int inv(int a, int n)
{
int d, x, y;
gcd(a, n, d, x, y);
return d == ? (x+n)%n : -;
} int C(int n, int m)
{ return mul_mod(mul_mod(fac[n], ifac[m]), ifac[n-m]); } void init()
{
fac[] = ifac[] = ;
for(int i = ; i < maxn; i++)
{
fac[i] = mul_mod(fac[i - ], i);
ifac[i] = inv(fac[i], MOD);
}
} int count(int u, int& size)//size是u为根的子树的节点总数
{//统计u为根的子树的排列方案
size = ;
int ans = ;
int d = sons[u].size();
vector<int> sonsize;
for(int i = ; i < d; i++)
{
int sz;
ans = mul_mod(ans, count(sons[u][i], sz));
size += sz;
sonsize.push_back(sz);
}
int sz = size - ;
for(int i = ; i < d; i++)
{
ans = mul_mod(ans, C(sz, sonsize[i]));
sz -= sonsize[i];
}
return ans;
} int main()
{
//freopen("in.txt", "r", stdin); init();
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d%d", &n, &m);
memset(fa, , sizeof(fa));
for(int i = ; i <= n; i++) sons[i].clear();
for(int i = ; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
fa[a] = b;
sons[b].push_back(a);
}
for(int i = ; i <= n; i++)
if(!fa[i]) sons[].push_back(i);
int size;
printf("%d\n", count(, size));
} return ;
}

代码君

书上后面又提到如果将上式完全展开,每个非根节点u都以(s(u)-1)!出现在分子一次,又以s(u)!出现在分母一次,约分后就只剩分母一个s(u)了。

这样f(root) = (s(root)-1)!/(s(1)s(2)...s(n)),又因为s(root) = n+1(因为除了n个人还有一个虚拟的0祖宗节点),

所以f(root) = n!/(s(1)s(2)...s(n)),还是用递归算出所有的s(i)

这样预处理一下40000以内的阶乘和乘法逆元即可。

 #include <bits/stdc++.h>

 using namespace std;

 const int maxn =  + ;
const int MOD = ; int n, m;
vector<int> sons[maxn];
int fa[maxn], fac[maxn], ifac[maxn], inverse[maxn], sonsize[maxn]; inline int mul_mod(int a, int b, int n = MOD)
{
a %= n; b %= n;
return (int)((long long)a * b % n);
} void gcd(int a, int b, int& d, int& x, int& y)
{
if(!b) { d = a; x = ; y = ; }
else{ gcd(b, a%b, d, y, x); y -= x*(a/b); }
} int inv(int a, int n = MOD)
{
int d, x, y;
gcd(a, n, d, x, y);
return d == ? (x+n)%n : -;
} int C(int n, int m)
{ return mul_mod(mul_mod(fac[n], ifac[m]), ifac[n-m]); } void init()
{
fac[] = ifac[] = ;
for(int i = ; i < maxn; i++)
{
fac[i] = mul_mod(fac[i - ], i);
inverse[i] = inv(i);
}
} void count(int u, int& size)
{//统计以u为根的子树节点个数
size = ;
int d = sons[u].size();
for(int i = ; i < d; i++)
{
int sz;
count(sons[u][i], sz);
size += sz;
}
sonsize[u] += size;
} int main()
{
//freopen("in.txt", "r", stdin); init();
int T;
scanf("%d", &T);
while(T--)
{
memset(fa, , sizeof(fa));
memset(sonsize, , sizeof(sonsize));
for(int i = ; i <= n; i++) sons[i].clear(); scanf("%d%d", &n, &m);
for(int i = ; i < m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
fa[a] = b;
sons[b].push_back(a);
}
for(int i = ; i <= n; i++)
if(!fa[i]) sons[].push_back(i);
int size;
count(, size);
//for(int i = 1; i <= n; i++) printf("%d\n", sonsize[i]);
int ans = fac[n];
for(int i = ; i <= n; i++) ans = mul_mod(ans, inverse[sonsize[i]]);
printf("%d\n", ans);
} return ;
}

代码君

UVa 11174 (乘法逆元) Stand in a Line的更多相关文章

  1. uva 11174 Stand in a Line

    // uva 11174 Stand in a Line // // 题目大意: // // 村子有n个村民,有多少种方法,使村民排成一条线 // 使得没有人站在他父亲的前面. // // 解题思路: ...

  2. UVA 11174 Stand in a Line 树上计数

    UVA 11174 考虑每个人(t)的所有子女,在全排列中,t可以和他的任意子女交换位置构成新的排列,所以全排列n!/所有人的子女数连乘   即是答案 当然由于有MOD 要求逆. #include & ...

  3. 数学:UVAoj 11174 Stand in a Line

    Problem J Stand in a Line Input: Standard Input Output: Standard Output All the people in the bytela ...

  4. Hdu 1452 Happy 2004(除数和函数,快速幂乘(模),乘法逆元)

    Problem Description Considera positive integer X,and let S be the sum of all positive integer diviso ...

  5. 2017 ACM-ICPC 亚洲区(西安赛区)网络赛 F. Trig Function(切比雪夫多项式+乘法逆元)

    题目链接:哈哈哈哈哈哈 _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ _(:з」∠)_ 哈哈哈哈哈哈,从9月16日打了这个题之后就一直在补这道题,今天终于a了,哈哈哈哈哈哈. ...

  6. 【ZOJ 3609】Modular Inverse 最小乘法逆元

    The modular modular multiplicative inverse of an integer a modulo m is an integer x such that a-1≡x  ...

  7. A. On The Way to Lucky Plaza 概率 乘法逆元

    A. On The Way to Lucky Plaza time limit per test 1.0 s memory limit per test 256 MB input standard i ...

  8. HDU 3923 Invoker(polya定理+乘法逆元(扩展欧几里德+费马小定理))

    Invoker Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 122768/62768K (Java/Other) Total Subm ...

  9. hdu_1452_Happy 2004 (乘法逆元

    Consider a positive integer X,and let S be the sum of all positive integer divisors of 2004^X. Your ...

随机推荐

  1. 瞧一瞧,看一看呐,用MVC+EF快速弄出一个CRUD,一行代码都不用写,真的一行代码都不用写!!!!

    瞧一瞧,看一看呐用MVC+EF快速弄出一个CRUD,一行代码都不用写,真的一行代码都不用写!!!! 现在要写的呢就是,用MVC和EF弄出一个CRUD四个页面和一个列表页面的一个快速DEMO,当然是在不 ...

  2. Careercup - Facebook面试题 - 5344154741637120

    2014-05-02 10:40 题目链接 原题: Sink Zero in Binary Tree. Swap zero value of a node with non-zero value of ...

  3. git@oschina.net源代码管理使用日记

    git的优势: 1 可以创建分支: 2 版本控制是基于每一次提交的,而不需要考虑每次提交了多少个文件. 下载: 下载网址为:http://git-scm.com/download,根据您的操作系统选择 ...

  4. PythonChallenge 1:恺撒密码的解码

    题目: 解题思路:根据图中的K→M,O→Q,E→G,我们可以发现K,O,E这三个字母都向后移动了2位.据说恺撒率先使用了这一加密方法,因此将其命名为恺撒密码.它的基本思想是:通过把字母移动一定的位数来 ...

  5. catci监控

    snmp安装:yum install net-snmp* 配置/etc/snmp/snmpd.conf:com2sec notConfigUser 192.168.79.129    publicac ...

  6. memmove和memcpy 以及strcmp strcpy几个库函数的实现

    memmove和memcpy 1.memmove 函数原型:void *memmove(void *dest, const void *source, size_t count) 返回值说明:返回指向 ...

  7. [设计模式] 13 责任链模式 Chain of Responsibility

    转    http://blog.csdn.net/wuzhekai1985   http://www.jellythink.com/archives/878 向项目经理提交了休假申请,我的项目经理向 ...

  8. linux源码阅读笔记 void 指针

    void 指针的步长为1,而其他类型的指针的步长与其所定义的数据结构有关. example: 1 #include<stdio.h> 2 main() 3 { 4 int a[10]; 5 ...

  9. node.js 安装、图文详解

    网上的教程很多,有些模糊不清,有些版本太旧,有些是.exe安装,本文讲述windows系统下简单nodejs .msi环境配置.最新版是Current version: v0.10.26.官网下载地址 ...

  10. java基础面试题(转)

    JAVA相关基础知识1.面向对象的特征有哪些方面 1.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解全部问题,而只是选择其中的一部分,暂时 ...