• 【BZOJ1005】明明的烦恼(HNOI2008)-Prufer序列+组合计数+高精度


    测试地址:明明的烦恼
    做法:本题需要用到Prufer序列+组合计数+高精度。
    这题就是HNOI2004-树的计数(BZOJ1211)的一个加强版,数据范围增大了,有些点还没有度数限制。但是我们也可以用类似的思路推出答案。我写的BZOJ1211题解看这里
    首先,Prufer序列中某些点的出现次数已经确定了,那么这些点之间的排列数量是一个可重排列,设一共有t个点出现次数已经确定,不妨设这些点为1~ts为这些点的出现次数之和,那么这些点之间的排列数量显然为s!/ti=1(di1)!,而这些排列在整个序列中的出现位置有Csn2那么多种,而剩下的n2s个位置可以从t+1~n,共nt个点中任选,所以最后的答案为:
    [s!/ti=1(di1)!]×Csn2×(nt)n2s
    稍微化一下式子可得:
    [(n2)!/[(n2s)!ti=1(di1)!]]×(nt)n2s
    然后用和我写的BZOJ1211的题解中类似的处理方法算出最后答案质因数分解的结果,乘起来算出答案即可。由于答案可能很大,所以需要用到高精度计算。最后还要注意判断一下无解,有两种情况是无解的:1.n1而某个di=0;2.s>n2。这样就可以解决此题了。
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    int n,d[2010],tot=0,t=0,a[2010][2010],sum[2010][2010],ans[2010],final[3010]={0},digit;
    ll p[2010];
    bool prime[2010]={0};
    
    void calc_prime(int limit)
    {
        for(ll i=2;i<=limit;i++)
        {
            if (!prime[i]) p[++tot]=i;
            for(ll j=1;j<=tot&&i*p[j]<=limit;j++)
            {
                prime[i*p[j]]=1;
                if (i%p[j]==0) break;
            }
        }
    }
    
    void mult(int x)
    {
        for(int i=1;i<=digit;i++)
            final[i]*=x;
        for(int i=1;i<=digit;i++)
            if (final[i]>9)
            {
                final[i+1]+=final[i]/10;
                final[i]%=10;
                if (i==digit) digit++;
            }
    }
    
    int main()
    {
        scanf("%d",&n);
        calc_prime(2000);
        for(int i=2;i<=2000;i++)
        {
            for(int j=1;j<=tot;j++)
            {
                sum[i][j]=0;
                int x=i;
                while(x%p[j]==0) sum[i][j]++,x/=p[j];
                a[i][j]=sum[i][j];
                sum[i][j]+=sum[i-1][j];
            }
        }
    
        int s=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&d[i]);
            if (d[i]!=-1) s+=d[i]-1,t++;
            if (n!=1&&d[i]==0) {printf("0");return 0;}
        }
    
        if (s>n-2) printf("0");
        else
        {
            for(int i=1;i<=tot;i++) ans[i]=sum[n-2][i];
            for(int i=1;i<=n;i++)
                if (d[i]!=-1)
                {
                    for(int j=1;j<=tot;j++)
                        ans[j]-=sum[d[i]-1][j];
                }
            for(int i=1;i<=tot;i++)
                ans[i]-=sum[n-2-s][i];
            for(int i=1;i<=tot;i++)
                ans[i]+=(n-2-s)*a[n-t][i];
            final[1]=1,digit=1;
            for(int i=1;i<=tot;i++)
                for(int j=1;j<=ans[i];j++)
                    mult(p[i]);
            bool flag=0;
            for(int i=digit;i>=1;i--)
            {
                if (final[i]) flag=1;
                if (flag) printf("%d",final[i]);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    线程安全的单例模式
    rsync 不真正同步,只显示更新的内容
    Python_元组、字典内建方法详解
    Python_元组、字典内建方法详解
    数组求差集
    svn数据库自动发布程序
    perl 比较目录
    被驱动表 拼接列无法走索引
    FILTER NESTLOOP 中驱动表问题
    Linux_SystemLogManager
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793546.html
Copyright © 2020-2023  润新知