题目描述 Description
求一颗有根树/树形图的拓扑序个数.
第一行一个n和一个素数P,表示这颗树有n个节点,要求拓扑序个数modP之后的结果.
接下来n-1行,每行有两个数字x和y,表示x是y的父亲.
保证1<=n<=1500000, n<P<2^31,P为质数.
一行一个数字,为该树形图拓扑序个数modP的结果.
样例1 4 100000007 1 2 1 3 2 4
样例2 6 100000007 1 2 2 3 1 4 3 5 5 6
样例1 3
样例2 5
每个非根节点的儿子个数平均较多,数据量较大,建议c/c++选手才用scanf的读入方式
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int md; long long gcd(long long y3) { long long x1 = 1,x2 = 0,y1 = 0,y2 = 1,x3 = md,t1,t2,t3,q; while(1) { if (y3==1) return y2; q=x3/y3; t1=x1-q*y1,t2=x2-q*y2,t3=x3-q*y3; x1 = y1,x2 = y2,x3 = y3; y1 = t1,y2 = t2,y3 = t3; } } long long an[1510000]; //long long bn[1510000]; long long n; struct edge { int v,next; }edge[1510000]; int head[1510000],e = 1; void increase(int u,int v) { edge[e].v = v; edge[e].next = head[u]; head[u] = e++; } int cn[1510000]; long long ans[1510000]; bool rd[1510000]; void dfs(int k) { cn[k] = ans[k] = 1; for(int t = head[k];t!=0;t = edge[t].next) { int v = edge[t].v; if(!cn[v]) dfs(v); cn[k]+=cn[v]; ans[k] = ans[k]*(gcd(an[cn[v]])+md)%md*ans[v]%md; } ans[k] = ans[k]*an[cn[k]-1]%md; } int Scan() { char ch; int a = 0; while((ch = getchar())>=47) { a = 10*a+ch-48; } return a; } int main() { n = Scan(),md = Scan(); long long i,j,k; //an[0] = bn[0] = 1; an[0] = 1; for(i = 1;i<=n;i++) { an[i] = an[i-1]*i%md; //bn[i] = bn[i-1]*(gcd(i)+md)%md; } for(i = 1;i<n;i++) { int a,b; a = Scan(),b = Scan(); rd[b]|=1; increase(a,b); } int fa; for(i = 1;i<=n;i++) if(!rd[i]) { fa = i; break; } dfs(fa); cout<<ans[fa]<<endl; return 0; }
原文:http://www.cnblogs.com/wos1239/p/4372641.html