洛谷P4099 [HEOI2013]SAO

题目描述

题解

我们可以把有关系的二元组连接,不考虑方向的话就是一棵树。所以我们可以做树形 $ ext{dp}$ : $f[i][j]$ 表示 $i$ 子树中 $i$ 的排名是 $j$ 的方案数,然后考虑转移。如果 $v$ 要在 $u$ 前的话,那就是:$$f[u][i+j]←sum_{k=1}^{j} f[u][i] imes f[v][k] imes (_{i+j-1}^{j}) imes (_{sz_u+sz_v-i-j}^{sz_u-i})$$
如果 $u$ 在 $v$ 前的话也是类似的。于是我们就只要对 $f[u][i]$ 做前缀和,即可将效率降至 $O(n^2)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1005,M=N<<1,P=1e9+7;char ch[3];
int T,n,c[N][N],hd[N],V[M],nx[M],W[M],t,f[N][N],sz[N],F[N];
int X(int x){return x>=P?x-P:x;}
void add(int u,int v,int w){
    nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
}
void dfs(int u,int fr){
    f[u][1]=sz[u]=1;
    for (int v,i=hd[u];i;i=nx[i]){
        if ((v=V[i])==fr) continue;dfs(v,u);
        for (int j=1;j<=sz[u];j++)
            for (int k=0;k<=sz[v];k++)
                if (W[i]) F[j+k]=X(F[j+k]+1ll*f[u][j]*f[v][k]%P*c[j+k-1][k]%P*c[sz[u]+sz[v]-j-k][sz[u]-j]%P);
                else F[j+k]=X(F[j+k]+1ll*f[u][j]*(f[v][sz[v]]-f[v][k]+P)%P*c[j+k-1][k]%P*c[sz[u]+sz[v]-j-k][sz[u]-j]%P);
        sz[u]+=sz[v];
        for (int j=1;j<=sz[u];j++) f[u][j]=F[j],F[j]=0;
    }
    for (int j=1;j<=sz[u];j++) f[u][j]=X(f[u][j]+f[u][j-1]);
}
void work(){
    scanf("%d",&n);
    for (int i=1,u,v;i<n;i++)
        scanf("%d%s%d",&u,ch,&v),u++,v++,
        add(u,v,ch[0]=='>'),add(v,u,ch[0]=='<');
    dfs(1,0);printf("%d
",f[1][n]);
    for (int i=1;i<=n;i++) hd[i]=0;t=0;
}
int main(){
    c[0][0]=1;
    for (int i=1;i<N;i++){
        c[i][0]=1;
        for (int j=1;j<=i;j++)
            c[i][j]=X(c[i-1][j]+c[i-1][j-1]);
    }
    for (cin>>T;T--;work());return 0;
}
原文地址:https://www.cnblogs.com/xjqxjq/p/12333538.html