题面:洛谷
计算方案个数,考虑动态规划:设\(f(u,j)\)表示在以\(u\)为根的子树中,\(u\)第\(j\)个被删除的方案数,考虑转移:
设当前\(u\)的删除序列长\(x\),\(v\)的删除序列长\(y\),枚举子树\(v\)中有\(j\)个数先于\(u\)删除,那么有:
\(case1.u<v\)
\[f(u,i+j)=C(i+j-1,i-1)*C(x+y-i-j,y-j)*f(u,i)*f(v,k)(k>j)\]
\(case2.u>v\)
\[f(u,i+j)=C(i+j-1,i-1)*C(x+y-i-j,y-j)*f(u,i)*f(v,k)(k<=j)\]
对\(k\)前缀和优化转移即可。
// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#define N 1005
using namespace std;
const int P=1e9+7;
int n,f[N][N],C[N][N],tmp[N];
#define gc() getchar()
inline int In(){
char c=gc(); int x=0,ft=1;
for(;c<'0'||c>'9';c=gc()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=gc()) x=x*10+c-'0';
return x*ft;
}
inline void Get_C(){
for(int i=0;i<=1e3;++i){
C[i][0]=1;
for(int j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
}
int h[N],sz[N],e_tot=0;
struct E{ int to,nex,op; }e[N<<1];
inline void init(){
e_tot=0;
memset(h,0,sizeof(h));
memset(f,0,sizeof(f));
}
inline void Add(int u,int v,int op){
e[++e_tot]=(E){v,h[u],op}; h[u]=e_tot;
e[++e_tot]=(E){u,h[v],!op}; h[v]=e_tot;
}
void dfs(int u,int fa){
sz[u]=1; f[u][1]=1;
for(int i=h[u],v;i;i=e[i].nex){
v=e[i].to; if(v==fa) continue; dfs(v,u);
if(!e[i].op){
for(int i=1;i<=sz[u];++i) tmp[i]=f[u][i],f[u][i]=0;
for(int i=1;i<=sz[u];++i)
for(int j=0;j<=sz[v];++j)
f[u][i+j]=(f[u][i+j]+1ll*C[i+j-1][i-1]*C[sz[u]+sz[v]-i-j][sz[v]-j]%P*tmp[i]%P*((f[v][sz[v]]-f[v][j]+P)%P)%P)%P;
}//u<v
else{
for(int i=1;i<=sz[u];++i) tmp[i]=f[u][i],f[u][i]=0;
for(int i=1;i<=sz[u];++i)
for(int j=0;j<=sz[v];++j)
f[u][i+j]=(f[u][i+j]+1ll*C[i+j-1][i-1]*C[sz[u]+sz[v]-i-j][sz[v]-j]%P*tmp[i]%P*f[v][j]%P)%P;
}//u>v
sz[u]+=sz[v];
}
for(int i=1;i<=sz[u];++i) f[u][i]=(f[u][i]+f[u][i-1])%P;
}
int main(){
int T=In(); Get_C(); char str[5];
while(T--){
n=In(); init();
for(int i=1,u,v;i<n;++i){
u=In(); scanf("%s",str); v=In();
++u; ++v; Add(u,v,(str[0]=='>'));
}
dfs(1,-1); printf("%d\n",f[1][n]);
}
return 0;
}
原文:https://www.cnblogs.com/pkh68/p/10533723.html