Kattis heapsoffun Heaps of Fun

Link
(f_u(x))表示(u)节点取值为(x)且该节点子树满足性质的概率,显然这是一个连续分布的概率密度函数。
(F_u(x)=int_0^xf_u(x))即概率分布函数,(G_u(x)=int_x^{b_u}f_u(x)=F_u(b_u)-F_u(x))
我们默认(f_u(x),F_u(x),G_u(x))的定义域为([0,b_u]),最后的答案就是(G_{root}(0))
对于叶子节点(u)而言,(f_u(x)=frac1{b_u})
对于非叶子节点(u)而言,(f_u(x)=frac1{b_u}prodlimits_{vin son_u}G_v(x))
不难发现(f_u(x),F_u(x),G_u(x))都是多项式。
暴力多项式乘法完成即可,时间复杂度为(O(n^3))

#include<cstdio>
#include<vector>
#include<cstring>
const int N=307,P=1000000007;
int n,a[N],inv[N];std::vector<int>e[N];
struct poly{int a[N],deg;poly(){memset(a,0,sizeof a),deg=0;}poly(int x){memset(a,0,sizeof a),a[0]=x,deg=1;}int&operator[](int x){return a[x];}};
struct node{poly a;int r;};
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int sub(int a,int b){return a-=b,a+(a>>31&P);}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
poly sub(poly f,poly g)
{
    poly h;h.deg=std::max(f.deg,g.deg);
    for(int i=0;i<h.deg;++i) h[i]=sub(f[i],g[i]);
    return h;
}
poly Int(poly f)
{
    poly g;g.deg=f.deg+1;
    for(int i=0;i<f.deg;++i) g[i+1]=mul(f[i],inv[i+1]);
    return g;
}
poly mul(poly f,poly g)
{
    poly h;h.deg=f.deg+g.deg-1;
    for(int i=0;i<f.deg;++i) for(int j=0;j<g.deg;++j) inc(h[i+j],mul(f[i],g[j]));
    return h;
}
int cal(poly f,int x)
{
    int s=0;
    for(int i=0,t=1;i<f.deg;++i,t=mul(t,x)) inc(s,mul(t,f[i]));
    return s;
}
node merge(node a,node b){return {mul(a.a,b.a),std::min(a.r,b.r)};}
node dfs(int u,int fa)
{
    node ans={poly(pow(a[u],P-2)),a[u]};poly t;
    for(int v:e[u]) if(v^fa) ans=merge(ans,dfs(v,u));
    return t=Int(ans.a),node{sub(cal(t,ans.r),t),ans.r};
}
int main()
{
    n=read(),inv[0]=inv[1]=1;
    for(int i=2;i<=300;++i) inv[i]=mul(P-P/i,inv[P%i]);
    for(int i=1;i<=n;++i) a[i]=read(),e[read()].push_back(i);
    printf("%d",dfs(e[0][0],0).a[0]);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12656487.html