zoukankan      html  css  js  c++  java
  • 树的计数(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]} imes C_{n-2-d[1]}^{d[2]} imes C_{n-2-d[1]-d[2]}^{d[3]} imes …… imes C_{n-2-d[1]-……-d[n-1]}^{d[n]}$

    得到

    $frac{(n-2)!}{sumlimits_{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("
    ");
        }
        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();
    }
    我已没有下降的余地
  • 相关阅读:
    IE8使用chrome内核渲染
    JS中的call()方法和apply()方法用法总结(挺好 转载下)
    解决雷达图文字显示不全问题
    echarts legend文字配置多个颜色(转)
    vue中Axios的封装和API接口的管理
    echarts 折线拐点收藏
    echarts 折线图自定义颜色与修改legend颜色
    MUI框架 按钮点击响应不好的问题解决办法
    ECharts将折线变平滑和去掉点的属性
    单例模式——创建型模式01
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11222262.html
Copyright © 2011-2022 走看看