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

Posted konjakjuruo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[uva11174]村民排队 递推+组合数+线性求逆元相关的知识,希望对你有一定的参考价值。

 

n(n<=40000)个村民排成一列,每个人不能排在自己父亲的前面,有些人的父亲不一定在。问有多少种方案。

 

 

父子关系组成一个森林,加一个虚拟根rt,转化成一棵树。

假设f[i]表示以i为根的子树的排列方案数。

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

化简,对每一个i,sum[i]-1在分子出现一次,sum[i]在分母出现一次。

Ans = n!/(sum1*sum2*sum3*...*sumn) 

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 typedef long long LL;
 8 const int mod=((int)1e9)+7,maxn=40000,N=40010;
 9 int first[N],sum[N],fa[N];
10 LL jc[N],inv[N];
11 int rt,al;
12 struct node{int x,y,next;}a[N];
13 
14 void ins(int x,int y)
15 {
16     a[++al].x=x;a[al].y=y;
17     a[al].next=first[x];first[x]=al;
18 }
19 
20 void dfs(int x)
21 {
22     sum[x]++;
23     for(int i=first[x];i;i=a[i].next)
24     {
25         dfs(a[i].y);
26         sum[x]+=sum[a[i].y];
27     }
28 }
29 
30 int main()
31 {
32     freopen("a.in","r",stdin);
33     
34     jc[1]=1;
35     for(int i=2;i<=maxn;i++) jc[i]=(jc[i-1]*i)%mod;
36     inv[1]=1;
37     for(int i=2;i<=maxn;i++)
38     {
39         inv[i]=((LL)(mod-mod/i))*inv[mod%i]%mod;
40     }
41     
42     int T,n,m,x,y;
43     scanf("%d",&T);
44     while(T--)
45     {
46         scanf("%d%d",&n,&m);
47         rt=n+1;
48         for(int i=1;i<=n;i++) fa[i]=-1;
49         al=0;
50         memset(first,0,sizeof(first));
51         for(int i=1;i<=m;i++)
52         {
53             scanf("%d%d",&x,&y);
54             fa[x]=y;
55             ins(y,x);
56         }
57         for(int i=1;i<=n;i++)
58             if(fa[i]==-1) fa[i]=rt,ins(rt,i);
59         memset(sum,0,sizeof(sum));
60         dfs(rt);
61         LL ans=jc[sum[rt]-1];
62         for(int i=1;i<=n;i++)
63         {
64             ans=ans*inv[sum[i]]%mod;
65         }
66         printf("%lld
",ans);
67     }
68     
69     return 0;
70 }

 

 

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>using namespace std;
typedef long long LL;const int mod=((int)1e9)+7,maxn=40000,N=40010;int first[N],sum[N],fa[N];LL jc[N],inv[N];int rt,al;struct node{int x,y,next;}a[N];
void ins(int x,int y){a[++al].x=x;a[al].y=y;a[al].next=first[x];first[x]=al;}
void dfs(int x){sum[x]++;for(int i=first[x];i;i=a[i].next){dfs(a[i].y);sum[x]+=sum[a[i].y];}}
int main(){freopen("a.in","r",stdin);jc[1]=1;for(int i=2;i<=maxn;i++) jc[i]=(jc[i-1]*i)%mod;inv[1]=1;for(int i=2;i<=maxn;i++){inv[i]=((LL)(mod-mod/i))*inv[mod%i]%mod;}int T,n,m,x,y;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);rt=n+1;for(int i=1;i<=n;i++) fa[i]=-1;al=0;memset(first,0,sizeof(first));for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);fa[x]=y;ins(y,x);}for(int i=1;i<=n;i++)if(fa[i]==-1) fa[i]=rt,ins(rt,i);memset(sum,0,sizeof(sum));dfs(rt);LL ans=jc[sum[rt]-1];for(int i=1;i<=n;i++){ans=ans*inv[sum[i]]%mod;}printf("%lld ",ans);}return 0;}





以上是关于[uva11174]村民排队 递推+组合数+线性求逆元的主要内容,如果未能解决你的问题,请参考以下文章

Uva 11174 Stand in a Line

数论干货线性方法求阶乘,逆元和组合数

Uva12034 (组合数取模)

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

UVA 11481 Arrange the Numbers(组合数学 错位排序)

UVa 557 Burger (概率+递推)