zoukankan      html  css  js  c++  java
  • HNOI2008明明的烦恼

    其实挺难的,对prufer得有一定的理解。

    首先我们知道prufer序列最多有n-2个点,其余知道度数的点出现的次数是di-1,定义prufer序列中剩余出现次数sum=n-2-∑(di-1)。这样我们可以近似于我们已经知道所有点的出现次数,用prufer的公式$frac{(n-2)!}{prod_{i=1}^n(d_i-1)!sum!}$,其中di是已知的度数,不一定由1到n,那个公式是搬过来的。

    这样的话我们忽略了一个问题,我们只是近似地认为所有点出现的次数已知,其实sum那一部分还有很多情况被忽略,因为我们并不知道剩下的位置到底是谁,那么,如果还剩下m个点不知道度数,那么在sum个位置任意填上他们的方案数为$m^{sum}$。把这两部分乘到一起就是答案。

    还有一个问题,这个东西是要高精的,这一坨坨的阶乘非常适合直接用阶乘拆分(至于如果你不知道什么是阶乘拆分,请看这个小链接),然后用qpow乘到一起,只是有点懒,直接for往上乘的也可以,没有qpow,也没有亿进制优化。

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int n,du[2000];
    int prime[1000],prime_num,sum,m;
    bool v[2000];
    struct Bigint{
        int a[100000],len;
        void clear(){
            memset(a,0,sizeof(a));
            a[1]=1;
            len=1;
        }
        friend void operator *(Bigint &x,int y){
            int delta=0;
            for(int i=1;i<=x.len;i++){
                x.a[i]=x.a[i]*y+delta;
                delta=x.a[i]/10;
                x.a[i]%=10;
            }
            while(delta){
                x.a[++x.len]=delta%10;
                delta/=10;
            }
            while(x.a[x.len]==0&&x.len>1)
                x.len--;
        }
        void out(){
            for(int i=len;i>=1;i--)
                printf("%lld",a[i]);
        }
    }ans;
    int read(){
        int sum=0,f=1;char x=getchar();
        while(x<'0'||x>'9'){
            if(x=='-') f=-1;
            x=getchar();
        }while(x>='0'&&x<='9'){
            sum=sum*10+x-'0';
            x=getchar();
        }return sum*f;
    }
    void doprime(int x){
        for(int i=2;i<=x;i++){
            if(!v[i]) prime[++prime_num]=i;
            for(int j=1;j<=prime_num&&i*prime[j]<=x;j++){
                v[i*prime[j]]=1;
                if(i%prime[j]==0) break;
            }
        }
    }
    signed main(){
        //freopen("data.in","r",stdin);
        //freopen("2.out","w",stdout);
        n=read();
        for(int i=1,x;i<=n;i++){
            x=read();
        /*    if(!x){
                puts("0");
                return 0;
            }*/
            if(x==-1) continue;
            du[++du[0]]=x;
            sum+=du[du[0]]-1;
            m++;
            if(n-2<sum){
                puts("0");
                return 0;
            }
        }
        sum=n-2-sum;
        m=n-m;
    //    cout<<m<<" "<<sum<<endl;
        doprime(n);ans.clear();
    /*    for(int i=1;i<=prime_num;i++)
            cout<<prime[i]<<" ";cout<<endl;*/
        for(int i=1;i<=prime_num;i++){
            int s=0;
            for(int j=n-2;j/=prime[i];) s+=j;
            //cout<<"s1="<<s<<endl;
            for(int j=1;j<=du[0];j++)
                for(int k=du[j]-1;k/=prime[i];) s-=k;
            for(int j=sum;j/=prime[i];) s-=j;
            for(int j=1;j<=s;j++)
                ans*prime[i];
        }
        for(int i=1;i<=sum;i++)
            ans*m;
        ans.out();
        puts("");
        return 0;
    }
    View Code
  • 相关阅读:
    常用DOS命令
    Intellij IDEA debug断点调试技巧与总结详解篇
    IDEA中常用函数的快捷键及自定义方法模板
    System.out.println()的真实含义
    盘点一下Github上开源的编程面试/学习相关的仓库
    IntelliJ IDEA
    JAVA基础——接口(全网最详细教程)
    Css基础
    CSS属性(根据继承性分为两类)
    HTML5新增标签(新增27个标签,废弃16个标签)
  • 原文地址:https://www.cnblogs.com/Yu-shi/p/11235529.html
Copyright © 2011-2022 走看看