亲戚(relative)
【题目背景】
Y 家是世界上最大的家族,HJZ 是其中一员。
现在 Y 家人想要拍一张全家福,却发现这是一个十分复杂的问题. . . . . .
【题目描述】
Y 家一共有 n 人
其中每个人最多有一个直系祖先。
Y 家的家规十分严格,在拍全家福时每个人必须排在其直系祖先后面。如 HZY 不
可以排在 HJZ 前面,但 Little_Meat_Circle 就可以排在 HJZ 前。
现在 HJZ 想知道可以有多少种合法的排队方案。你只需要给出方案数对 109 + 7 取模的结果。
【输入格式】
从文件 relative.in 中读入数据。
第一行一个正整数 n 表示 Y 家的人数。
第二行 n 个整数 fi 表示第 i 个人的直系祖先编号。若 fi = 0 则表示第 i 个人没有 直系祖先。保证 fi , i 。
【输出格式】
输出到文件 relative.out 中。
一行一个整数,表示合法的方案数对 109 + 7 取模的结果。
【样例 1 输入】
4
0 1 1 0
【样例 1 输出】
8
题解:
首先,一个节点在以它为根的子树的方案中必为第一位
所以以它为根的子树的方案等于:
将所有子节点对应的子树的序列混合起来的方案数
因为序列顺序不能改变,所以可以变成组合问题
假设一个子树对应的序列a长为x,一个子树对应的序列b长为y,组成一个x+y的序列
所以方案数为:从x+y个位置中选x个(或y个)=>C(x+y,x)
因为这只是一对序列的方案,所以要乘f[a]*f[b]
这里f[x]是指x点的子树的方案数
在多叉树中,分叉可能大于2,这没有关系
先算出两个儿子的值,合并起来,记下合并后的方案数和大小,作为一个节点与下一个儿子合并
sum=(sum*f[v])*(C(tmp,p)) (p是子树大小,tmp是当前大小+p,sum是当前方案数)
最后f[x]=sum;
下一个问题,这个过程已经是O(n)了,求组合数如果O(n)会超时
方法是:
C(n,r)=n!/((n-r)!*r!)
n!用O(n)预处理,分母就用递推式
A[i]=(Mod-Mod/i)*A[Mod%i]%Mod
在O(n)时间内求出阶乘逆元
组合数就可以O(1)搞定了
总复杂度为O(n)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct Node 8 { 9 int next,to; 10 }edge[400001]; 11 int head[200001],Mod=1000000007,n,num; 12 long long f[200001],A[200001],B[200001]; 13 void add(int u,int v) 14 { 15 num++; 16 edge[num].next=head[u]; 17 head[u]=num; 18 edge[num].to=v; 19 } 20 long long C(int x,int r) 21 { 22 if (x==r) return 1; 23 if (r==0) return 1; 24 long long s=B[x]; 25 s=(s*A[x-r])%Mod; 26 s=(s*A[r])%Mod; 27 //cout<<x<<' '<<r<<' '<<s<<endl; 28 return s; 29 } 30 int dfs(int x,int pa) 31 {int i,p; 32 int tmp=0; 33 long long sum=1; 34 for (i=head[x];i;i=edge[i].next) 35 { 36 int v=edge[i].to; 37 if (v!=pa) 38 { 39 p=dfs(v,x); 40 //cout<<v<<' '<<f[v]<<' '<<p<<endl; 41 tmp+=p; 42 sum=(((sum*f[v])%Mod)*C(tmp,p))%Mod; 43 } 44 } 45 f[x]=sum; 46 //cout<<sum<<' '<<x<<endl; 47 return tmp+1; 48 } 49 int main() 50 {int i,x,j; 51 //freopen("relative.in","r",stdin); 52 //freopen("relative.out","w",stdout); 53 cin>>n; 54 for (i=1;i<=n;i++) 55 { 56 scanf("%d",&x); 57 add(x,i); 58 } 59 B[0]=1; 60 for (i=1;i<=n;i++) 61 B[i]=(B[i-1]*i)%Mod; 62 A[1]=1; 63 for (i=2;i<=n;i++) 64 A[i]=((Mod-(Mod/i))*(long long)A[Mod%i])%Mod; 65 for (i=2;i<=n;i++) 66 A[i]=(A[i]*A[i-1])%Mod; 67 dfs(0,0); 68 cout<<f[0]; 69 }