樹的計數(prufer序列 或 purfer序列)


 題解

首先我們要知道一條性質,prufer序列中的某個點出現次數為該點在樹中度數-1

感性理解一下,其實按照prufer序列求法自己推一下就出來了

設題目里給的度為$d[]$

先將所有的d--

然后按照排列組合得出來

這是多重集排列數

首先從n-2中選擇d[1]個數是$C_{n}^{d[1]}$然后再從剩余n-d[1]中選d[2] $C_{n-d[1]}^{d[2]}$依次類推

$C_{n-2}^{d[1]}\times C_{n-2-d[1]}^{d[2]}\times C_{n-2-d[1]-d[2]}^{d[3]}\times ……\times C_{n-2-d[1]-……-d[n-1]}^{d[n]}$

得到

$\frac{(n-2)!}{\sum\limits_{i=1}^{n}d[i]!}$

高精轉移就完了

還是過不了?

一些特判:

首先該題會有無解的情況

然后當只有一個點時方案數為1

然后當出現度數為0的點時方案數要特殊處理

以下是本人丑陋的代碼

#include<bits/stdc++.h>
#define ll long long
#define N 10
#define P 1
using namespace std;
ll n,m,d[20000],cnt=0;
bool flag[20000];
struct bignum
{
    ll n[200000],l;
    bignum(){l=1,memset(n,0,sizeof(n));}
    void clear(){while(l>1&&!n[l-1]) l--;}
    void print()
    {
        printf("%lld",n[l-1]);
        for(ll i=l-2;i>=0;i--)
        printf("%0*lld",P,n[i]);
        printf("\n");
    }
    bignum operator = (ll x)
    {
        l=0;    
        while(x)
        {
            n[l++]=x%N;
            x/=N;
        }
        return *this;
    }
    bignum operator +(bignum x) const
    {
        bignum t=*this;
        if(x.l>t.l) t.l=x.l;        
        for(ll i=0;i<t.l;i++)
        {
            t.n[i]+=x.n[i];
            if(t.n[i]>=N)
            {
                t.n[i+1]+=t.n[i]/N;
                t.n[i]%=N;
            }
        }
        return t;
    }
       bignum operator * (const ll& b)
      {
        bignum c;
           c.l=0;
        for(ll i=0,g=0;g||i<l;i++)
        {
            ll x;
            if(i<l)x=n[i]*b+g;
            else x=g;
            c.n[c.l++]=x%N;
            g=x/N;
        }
        return c;
    }
    bignum operator *(bignum x) const
    {
        bignum t=*this,tep;
        tep.l=t.l+x.l+1;
        for(ll i=0;i<t.l;i++)
            for(ll j=0;j<=x.l;j++)
            {
                tep.n[i+j]+=t.n[i]*x.n[j];
            }
        for(ll i=0;i<tep.l;i++)
        {
            tep.n[i+1]+=tep.n[i]/N;
            tep.n[i]%=N;
        }
        tep.clear();
        return tep;
    }
    bool operator <(bignum x) const
    {
        bignum t=*this,tep;
        if(t.l!=x.l)    return t.l<x.l;
        for(ll i=t.l-1;i>=0;i--)
        {
            if(t.n[i]!=x.n[i]) return t.n[i]<x.n[i];
        }
        return 0;
    }
    bool operator >(bignum x) const
    {
        bignum t=*this;
        if(t.l!=x.l) return t.l>x.l;
        for(ll i=t.l-1;i>=0;i--)
        {
            if(t.n[i]!=x.n[i]) return t.n[i]>x.n[i];
        }
        return 0;
    }
    bignum operator -(bignum x) const
    {
        bignum t=*this;
        if(t<x) printf("-"),swap(t,x);
        ll jie=0;
        for(ll i=0;i<t.l;i++)
        {
            t.n[i]-=x.n[i];
            while(t.n[i]<0)
            {
                t.n[i]+=N;
                jie++;
            }
            t.n[i+1]-=jie;
            jie=0;;
        }
        t.clear();
        return t;
    }
    bignum operator /(const ll &x)
    {
        bignum t=*this,r;
        ll tmp=0;
        r.l=t.l;
        for(ll i=t.l-1;i>=0;i--){
            tmp+=t.n[i];
            if(tmp>=x){
                r.n[i]=tmp/x;
                tmp%=x;
            }
            tmp*=N;
        }
        r.clear();
        return r;
    }
}ans;
bignum jie(ll x)
{
    bignum t;t=1;
    for(ll i=2;i<=x;i++){
        t=x*i;
    }
    return t;
}
int main()
{
    memset(flag,0,sizeof(flag));
    ll sum=0,you0=0;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld",&d[i]);
        if(d[i])flag[i]=1,cnt++;
        else you0=1;
        d[i]--,sum+=d[i];
        
    }
    if(you0&&n==1){
        cout<<1<<endl;
        return 0;
    }
    if(sum!=n-2||you0) 
    {
        cout<<0<<endl;
        return 0;
    }
    ans=1;
    for(ll i=2;i<=cnt-2;i++)
        ans=ans*i;
    for(ll i=1;i<=n;i++){
        if(flag[i])
        for(ll j=2;j<=d[i];j++)
                ans=ans/j;
    }
    ans.print();
}

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com