HNOI2008明明的煩惱

其實挺難的,對prufer得有必定的理解。html

首先咱們知道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,那個公式是搬過來的。c++

這樣的話咱們忽略了一個問題,咱們只是近似地認爲全部點出現的次數已知,其實sum那一部分還有不少狀況被忽略,由於咱們並不知道剩下的位置究竟是誰,那麼,若是還剩下m個點不知道度數,那麼在sum個位置任意填上他們的方案數爲$m^{sum}$。把這兩部分乘到一塊兒就是答案。ide

還有一個問題,這個東西是要高精的,這一坨坨的階乘很是適合直接用階乘拆分(至於若是你不知道什麼是階乘拆分,請看這個小連接),而後用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
相關文章
相關標籤/搜索