[BZOJ1005][HNOI2008]明明的烦恼(prufer序列+组合数学+高精度)

题目描述

传送门

题解

参考资料:
http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/23/3278557.html
几个重要的性质:
一种prufer序列只能对应一颗生成树,那么求生成树的个数就是求不同的prufer序列的个数。
一个点的度数减一表示它在prufer序列中出现了几次
那么利用组合公式可以推出求出不同prufer序列的公式。
显然这个数非常大,牵扯到高精度,那么我们可以十分机智地将分数线上下分解质因数,然后做高精度乘法即可。

代码

#include
#include
#include
using namespace std;

const int max_n=1005;

int n,sum,cnt,q,temp;
int c[max_n],d[max_n],pri[max_n];
struct hp{int a[100000];}ans;

inline void cheng(hp &ans,int b)
{
    for (int i=1;i<=ans.a[0];++i) ans.a[i]*=b;
    for (int i=1;i<=ans.a[0];++i)
    {
        ans.a[i+1]+=ans.a[i]/10;
        ans.a[i]%=10;
    }
    while (ans.a[ans.a[0]+1])
    {
        ans.a[0]++;
        ans.a[ans.a[0]+1]+=ans.a[ans.a[0]]/10;
        ans.a[ans.a[0]]%=10;
    }
}
int main()
{
    scanf("%d",&n);
    if (n==1)
    {
        scanf("%d",&c[1]);
        if (c[1]==0||c[1]==-1) printf("1\n");
        else printf("0\n");
        return 0;
    }
    for (int i=1;i<=n;++i)
    {
        scanf("%d",&c[i]);
        if (!c[i])
        {
            printf("0\n");
            return 0;
        }
        if (c[i]!=-1)
        {
            d[++cnt]=c[i]-1;
            sum+=d[cnt];
        }
        else q++;   
    }
    if (n-2printf("0\n");
        return 0;
    }
    for (int i=1;i<=cnt;++i)
        for (int j=2;j<=d[i];++j)
        {
            temp=j;
            for (int k=2;k<=j&&temp!=1;++k)
                while (temp%k==0) pri[k]--,temp/=k;
        }
    for (int i=n-2-sum+1;i<=n-2;++i)
    {
        temp=i;
        for (int j=2;j<=i&&temp!=1;++j)
            while (temp%j==0) pri[j]++,temp/=j;
    }
    ans.a[0]=1; ans.a[1]=1;
    for (int i=1;i<=n;++i)
        while (pri[i])
        {
            pri[i]--;
            cheng(ans,i);
        }
    for (int i=1;i<=n-2-sum;++i)
        cheng(ans,q);
    for (int i=ans.a[0];i>=1;--i)
        printf("%d",ans.a[i]);
    putchar('\n');
}

总结

分解质因数的姿势注意一下。

你可能感兴趣的:(题解,省选,高精度,组合数学,prufer序列)