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.
3 2
2 1
3 1
3 0
3 1
2 1
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;
}
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
33 2
2 1
3 1
3 0
3 1
2 1
Output for Sample Input
26
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;
}
相关文章推荐
- ACM: uva 11375 - Matches
- ACM: uva 11401 - Triangle Counti…
- ACM: uva 11538 - Chess Queen
- ACM: uva 10534 - Wavio Sequence
- ACM: uva 1424 - Salesmen
- web新内容
- 深入分析 Java 中的中文编码问题(1)
- ACM: uva 11584 -
- ACM: uva 1468 - Restaurant
- ACM: poj 3972 -&n…
- jquery 1.6 后 checkbox 使用attr("checked"),undefined.
- ACM: poj 2786 -&n…
- ACM: uva 1432 -&n…
- ACM: uva 1451 - Average
- ACM: uva 10391 - Compound Words
- ACM: uva 10763 -&…
- ACM: uva 10125 - Sumsets
- Java发展历史
- ACM: uva 10827 -&…
- ACM: uva 1325 -&n…