BZOJ1211树的计数

裸的prufer结论。

给个小链接prufer序列 ,里面有一个性质4就是本题答案,严谨证明可以上网找一找,如果从多组组合角度理解也可以。

剩下的就是特判,n==1时,du==0,1个,du!=0,废了。有du==0,废了。度数和大于(还是不等于来着?)2*(n-1),废了。拿到67分……。

接着就是求那个式子了,我有一套O(n)拆一个阶乘的理论。那这个就是O(n^2)了呗。   

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define ll long long 
using namespace std;
ll ans=1,n,du[250],sum,prime[300],prime_num;
bool v[350];
ll read(){
    ll sum=0;int 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;
        }
    }
}
ll qpow(ll x,ll k){
    ll ans=1;
    for(;k;k>>=1,x=x*x)
        if(k&1) ans=ans*x;
    return ans;
}
int main(){
    n=read();
    if(n==1){
        du[1]=read();
        if(!du[1]) puts("1");
        else puts("0");
        return 0;
    }
    for(int i=1;i<=n;i++){
        du[i]=read();
        if(!du[i]){
            puts("0");
            return 0;
        }
        sum+=du[i];
    }
    if(sum!=2*(n-1)){
        puts("0");
        return 0;
    }
    doprime(n);
    for(int i=1;i<=prime_num;i++){
        int s=0;
        for(int j=n-2;j/=prime[i];) s+=j;
        for(int j=1;j<=n;j++)
            for(int k=du[j]-1;k/=prime[i];) s-=k;
        ans=ans*qpow(prime[i],s);
    }printf("%lld",ans);
    return 0;
}
View Code

          

原文地址:https://www.cnblogs.com/Yu-shi/p/11234665.html