UVA 11174 Stand in a Line

  題目大意:有n我的構成森林關係。如今要把他們排成一列,使兒子不在父親前面,求方案數。n<=40000。ios

  驚歎數學之妙。ide

  首先看見森林,不如來一個超級點作根。spa

  設f[i]表示處理完i與i的子樹的方案數,size[i]表示子樹大小,j是i的兒子。3d

  首先對於兩棵子樹,它們之間是互不影響的,因此方案數應該相乘,這部分表示出來就是:code

    

  而後思考對於一種對於每一個j的內部順序已經肯定,求i有多少种放法?這就至關於一個可重集合的模型(在j內的至關於一個重複元素):blog

  

  而後兩部分用乘法原理乘起來,就是f[i]:get

  

  這個就能夠寫這道題了。數學

  但實際上能夠進一步化簡?咱們來考慮把一個f[j]拆開。設j的兒子是x:string

  

  而後f[i]的式子裏的size[j]!能夠被(size[j]-1)!消成size[j]。it

  思惟發散一下,f[i]內的size!和(size-1)!都會被消成1/size。

  最後的答案是f[0]:

  

  由於(size[0]-1)!=n!,最後答案就是:

  

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
#define FILE "11174"
using namespace std;

const int N = 40010;
const int Mod = 1000000007;
struct Node{int to,next;}E[N];
int n,m,head[N],tot;
int J[N],Ny[N],size[N],fa[N];

inline int gi(){
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}

inline void link(int u,int v){
  E[++tot]=(Node){v,head[u]};
  head[u]=tot;
}

inline void pre(){
  Ny[1]=J[1]=1;
  for(int i=2;i<N;++i){
    J[i]=1ll*J[i-1]*i%Mod;
    Ny[i]=1ll*(Mod-Mod/i)*Ny[Mod%i]%Mod;
  }
}

inline void dfs(int x){
  size[x]=1;
  for(int e=head[x];e;e=E[e].next)
    dfs(E[e].to),size[x]+=size[E[e].to];
}

inline void solve(int Ans=0){
  memset(fa,0,sizeof(fa));
  memset(head,0,sizeof(head));
  n=gi();m=gi();tot=0;
  for(int i=1;i<=m;++i)fa[gi()]=gi();
  for(int i=1;i<=n;++i)link(fa[i],i);
  dfs(0);Ans=J[n];
  for(int i=1;i<=n;++i)Ans=1ll*Ans*Ny[size[i]]%Mod;
  printf("%d\n",(Ans+Mod)%Mod);
}

int main()
{
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
  pre();int Case=gi();while(Case--)solve();
  fclose(stdin);fclose(stdout);
  return 0;
}
Stand in a Line
相關文章
相關標籤/搜索