[説明]ニワトリ生息(Pruferシーケンス番号+スターリング)のCJOI2019の集大成を

[説明]ニワトリ生息(Pruferシーケンス番号+スターリング)のCJOI2019の集大成を

トピックの背景

  舒服了。

タイトル説明

あなたはn個の点に無根の木を持って、各点は、ラベル(1〜n)を持っています。
今、あなたが知っている、m個のリーフノードの合計、異なる形式のプログラムを必要と木の数があります。
答えがする(9 + 10 ^ 7 \)\剰余を。

:ここではいくつかの可能な便利な定義されている
リーフ:ポイント1度は。
異なる:同じ木の二つの数字であれば\(TL =(V、E_1)、T2 =(V、E_2)\)、\ (TL \ NEQ T2 \)とが存在する場合にだけ\((U、V)は\ E_1で、(U、V )\ E_2 notin \)

入力形式

合計行は、最初の行は、mがポイントと葉の数の合計数を表し、2つの数値を含んでいるN。
データは、木を確保するために存在している必要があります。

出力フォーマット

ライン整数、出力への回答(9 + 10 ^ 7 \)\モジュロ結果。

サンプル入力1

5 3

サンプル出力1

60

サブタスク

以下のための\(10 \%\)データ、保証する\(N、M <= 5
\)をする(20 \%\)\確実にするために、データを\(N、M <= 10
\)をする(40 \%を\ \)データを、確実にするために\(N、M <= 20
\)をする(60 \%の\)\確実にするために、データを\(N、M <= 5000
\)を追加するための\(10 \%の\)データ、確保\(M = 2 \)
の追加のために\(10 \%\)を保証するために、データを\(M = N-1 \の
) 追加のための\(10 \%\)を保証するために、データ\を(N、M> = 5 \)
(100 \%の\)\確実にするために、データを\(N、M <= 2 \回10 ^ 5 \)を

\(溶液\)

木の列挙は、一Prufer配列によって変換され、第二スターリングPruferシーケンス番号に従って解決されます。

Pruferシーケンス

参照ツリーが得られると仮定\(T \)を、我々はこのような動作により、シーケンスを取得することができ、配列およびその対応する木が1です。つまり、任意の二つの異なる法的Pruferシーケンスは、二つの異なる木に対応させていただきます。彼はここに木が番号が付けられていることを指摘しました。

ツリーにおいて、リーフノードの最小数を選択し、親ノードは、それPrufer配列に加え、リーフノードを削除します。

2つだけのノードが(片側のみが同定されていない)、この時点で決定することができるまでツリー全体の形状を有しています。

そう数が得られる\(N-2 \)番目の配列を、この順序木形1に対応。この\(N-2 \)配列要素が構成することができる
[N ^ {N-2 \
} \] の組合せ。

対応の法則によると、それは言うことであるツリー内のNノードは無符号合計である\(N ^ {N-2 } \) の組み合わせ

私たちは、シーケンス、それが表示された回数-1ノード内Pruferシーケンス中程度の重要性を見てください。だから今の質問はなった、私が保証します\(m個\) Pruferシーケンスを表示されませんノードを。

第二種のスターリング数

(\ \ {Bmatrixを}始めるN \ \\ m個\端{Bmatrix}) を表し、\(N-を\)要素はに分割される\(m個\)非空集合プログラム番号。

ここでのメッセージは表示されません:要素は、区別なしのコレクション異なっています。

漸化式

\ [{N \ブレースM} = {N-1 \ブレースM-1} + M {N-1 \ブレースM} \]

証明:参照してくださいyybのブログを。

包含と除外\(O(n)と\) またはNTT \(O(N \ N-ログ)\) 追求)

\ [S_2(N、M)= \ {Bmatrixを}始めるN \\ m個\端{Bmatrix} = \ FRAC 1 {M!} \ sum_ {i = 0} ^ M(-1)^ I {(MI) ^ N} {m個の\は、Iを選択} \]

証明:参照してくださいyybのブログを。

最終的な回答
の\ [(nm)を!\タイムズ
\回{N-2 \ブレースNM} \ {N Mを選択してください\}] 最後のボックス(セット)無差のスターリング数は、しかし、ここでは異なるため、それはで乗算されなければならないので、\((nm)を!\) それを構成しています。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
const int mod=1e9+7;
const int maxn=2e5+5;
int jc[maxn];
int inv[maxn];
int n,m,ans,k;

typedef const int& ct;
inline int ksm(int base,ct p){
      register int ret=1;
      for(register int t=p;t;t>>=1,base=1ll*base*base%mod)
        if(t&1) ret=1ll*ret*base%mod;
      return ret;
}

int C(int n,int m){
      if(n<m) return 0;
      return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}

int S(ct n,ct m){
      register int ret=0;
      for(register int t=0;t<=m;++t)
        if(t&1) ret=(0ll+ret-1ll*ksm(m-t,n)*C(m,t)%mod+mod)%mod;
        else ret=(0ll+ret+1ll*ksm(m-t,n)*C(m,t)%mod+mod)%mod;
      return 1ll*ret*inv[m]%mod;
}

int main(){
#ifndef ONLINE_JUDGE
      freopen("dfzjj.in","r",stdin);
      freopen("dfzjj.out","w",stdout);
#endif
      jc[0]=1;
      inv[0]=1;
      for(register int t=1;t<maxn;++t) jc[t]=1ll*jc[t-1]*t%mod,inv[t]=1ll*inv[t-1]*ksm(t,mod-2LL)%mod;
      n=qr();m=qr();
      ans=1ll*jc[n-m]*C(n,m)%mod*S(n-2,n-m)%mod;
      printf("%d\n",ans);
      return 0;
}

おすすめ

転載: www.cnblogs.com/winlere/p/10926638.html