[Heoi2013]Sao

$ f_{x,j} $ 表示以x为根的子树 x这个点在子树里的排名为j的方案总数

考虑x和儿子的合并

转移时要开一个临时的数组 $ t[] $ 来临时存一下数据

当儿子在x后面时

$$ t_{j+k}=\sum_{j=1}^{size[x]}\sum_{k=0}^{size[son]}C_{j+k-1}^k*C_{size[son]-k+size[x]-j}^{size[son]-k}*f_{x,j}*suf{son,k+1} $$

当儿子在x前面时

$$ t_{j+k}=\sum_{j=1}^{size[x]}\sum_{k=1}^{size[son]}C_{j+k-1}^{k}C_{size[x]-j+size[son]-k}^{size[son]-k}*pre_{son,k}*f_{x,j} $$

#pragma GCC optimize("O3")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <ctime>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define rint register int
#define dd double
using namespace std;
char rea=0;
inline void read(int &x)
{
    x=0;
    while(rea<'0'||rea>'9') rea=getchar();
    while(rea>='0'&&rea<='9') x=x*10+rea-'0',rea=getchar();
}
inline void readchar(char &x)
{
    while(rea!='<'&&rea!='>') rea=getchar();
    x=rea;
}
const int N=1006;
const int mod=1000000007;
int first[N],nt[N*2],ver[N*2],w[N*2],e;
void addbian(int u,int v,int _w)
{
    ver[e]=v; w[e]=_w;
    nt[e]=first[u];
    first[u]=e++;
}

ll qpow(ll a,int ci)
{
    ll ans=1;
    while(ci)
    {
        if(ci&1)
            ans=ans*a%mod;
        a=a*a%mod;
        ci>>=1;
    }
    return ans%mod;
}
ll jie[N],jieni[N];
void chu()
{
    int i;
    jie[0]=1;
    for(i=1;i<N;++i)
        jie[i]=jie[i-1]*i%mod;
    jieni[N-1]=qpow(jie[N-1],mod-2);
    for(i=N-2;i;--i)
        jieni[i]=jieni[i+1]*(i+1)%mod;
    jieni[0]=1;
}
inline ll C(int n,int m)
{
    if(n<0||m<0||n<m) return 0;
    return jie[n]*jieni[m]%mod*jieni[n-m]%mod;
}

int T;
int n;

ll f[N][N],t[N];
ll pr[N][N],ho[N][N];
int fa[N],size[N];
void dp(int x)
{
    f[x][1]=1; size[x]=1;
    int i,j,k,p;
    for(i=first[x];i!=-1;i=nt[i])
    {
        if(ver[i]==fa[x])
            continue;
        fa[ver[i]]=x;
        dp(ver[i]);
        for(j=size[x]+size[ver[i]];~j;--j)
            t[j]=0;
        if(w[i])
        {
            for(j=size[x];j;--j)
                for(k=size[ver[i]]-1;~k;--k)
                    t[j+k]=(t[j+k]+C(j+k-1,k)*C(size[ver[i]]-k+size[x]-j,size[ver[i]]-k)%mod*f[x][j]%mod*ho[ver[i]][k+1]%mod)%mod;
        }
        else //儿子比x小 
        {
            for(j=size[x];j;--j)
                for(k=size[ver[i]];k;--k)
                    t[j+k]=(t[j+k]+f[x][j]*pr[ver[i]][k]%mod*C(j+k-1,k)%mod*C(size[x]-j+size[ver[i]]-k,size[ver[i]]-k)%mod)%mod;
        }
        size[x]+=size[ver[i]];
        for(j=size[x];j;--j)
            f[x][j]=t[j];
    }
    
    for(i=1;i<=size[x];++i)
        pr[x][i]=(f[x][i]+pr[x][i-1])%mod;
    for(i=size[x];i;--i)
        ho[x][i]=(f[x][i]+ho[x][i+1])%mod;
}

int main(){
    
    //freopen("in.in","r",stdin);
    //freopen("zout.out","w",stdout);
    
    rint i,j;
    int tin1,tin2; char op;
    chu();
    
    read(T);
    while(T--)
    {
        mem(first,-1); e=0;
        mem(f,0); mem(fa,0);
        mem(size,0); mem(ho,0); mem(pr,0);
        read(n);
        for(i=1;i<n;++i)
        {
            read(tin1); readchar(op); read(tin2);
            ++tin1; ++tin2;
            addbian(tin1,tin2,(op=='<'));
            addbian(tin2,tin1,(op=='>'));
        }
        fa[1]=-1;
        dp(1);
        
        ll as=0;
        for(i=1;i<=size[1];++i)
            as=(as+f[1][i])%mod;
        printf("%lld\n",as%mod);
    }
}
AA

表示脑子有些混沌...

 

posted @ 2017-10-28 21:04  A_LEAF  阅读(568)  评论(0编辑  收藏  举报