1. 程式人生 > >UVA11174 Stand in a Line

UVA11174 Stand in a Line

連結

題解

首先我建一個虛點,設其為森林中所有樹的父親,那現在就成一棵樹了 設f(x)為以節點x為根的子樹的答案 那麼x點本身肯定排在所有子節點的前面,現在只需考慮其子樹中的點怎麼排列,子樹內部先排列,然後再把這些排列交錯著插起來,子樹之間是獨立的,如果把同一棵子樹上的點看作相同的點,那麼這就是有重複元素的排列組合,假設子樹的大小為s(c1),s(c2)...s(ck),那麼

f(x)=[i=1kf(ci)][s(x)1]!i=1ks(ci)! 其中
k
是子節點個數,ci表示第i個兒子,s(x)表示子樹大小 使用代入法,就會發現當計算f(x)時,分子上會出現一個[s(x)1]!, 在計算f(father(x))時分母上會出現一個s(x)! 約分之後分母上剩下一個s(x)[s(root)1]!不會被約去,因為root沒有父親節點 這樣最終答案就是n!i=1ns(i)

程式碼

//數學題
#include <bits/stdc++.h>
#define maxn 100010
#define mod 1000000007ll
#define cl(x) memset(x,0,sizeof(x)) #define ll long long using namespace std; ll head[maxn], to[maxn], nex[maxn], etot, N, M, mark[maxn], sz[maxn], ans, inv[maxn]; void adde(ll a, ll b){to[++etot]=b;nex[etot]=head[a];head[a]=etot;} ll read(ll x=0) { ll c, f=1; for(c=getchar();!isdigit(c);c=getchar())if
(c=='-')f=-1; for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48; return f*x; } void preprocess() { ll i; inv[1]=1; for(i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod; } void init() { ll i, a, b; cl(head), cl(nex), etot=0, cl(mark), cl(sz), ans=1; N=read(), M=read(); for(i=1;i<=M;i++)a=read(), b=read(), adde(b,a), mark[a]=1; for(i=1;i<=N;i++)if(!mark[i])adde(N+1,i); } void dfs(ll pos) { ll p; sz[pos]=1; for(p=head[pos];p;p=nex[p]) { dfs(to[p]); sz[pos]+=sz[to[p]]; } if(pos!=N+1)ans=ans*inv[sz[pos]]%mod; } void show() { ll i; for(i=1;i<=N;i++)ans=ans*i%mod; printf("%lld\n",ans); } int main() { ll T=read(); preprocess(); while(T--) { init(); dfs(N+1); show(); } return 0; }