题解:AT_arc130_d [ARC130D] Zigzag Tree

题意

给定一棵树,统计满足条件的点权序列的数量:

  • 点权为 \(1\)\(n\) 的排列。
  • 对于任意点 \(u\),其点权要么大于所有邻居,要么小于所有邻居。

\(n \leq 3000\)

题解

我们称点权大于所有邻居的点为大点,点权小于所有邻居的点为小点

一个点一定不会同时成为大小点,同一条边连接的两个点类型不同。

\(f_{u,i,0/1}\) 表示以 \(u\) 为根的子树,\(u\)子树内排名为 \(i\),点 \(u\) 为小点或大点的方案数。

发现一定有 \(f_{u,i,0}=f_{u,i,1}\),因此可以把最后一维去掉。

类似树上背包的转移,设 \(g_i=f_{u,i}\) 为儿子 \(v\)\(u\) 转移前的 \(f_u\)

对于每个 \(f_{u,j}\),枚举加入 \(v\) 子树前 \(u\) 的排名 \(x\),有:

\[f_{u,j}= \sum_{\max(j-sz_v,1) \leq x \leq \min(j-1,sz_u)} C_{j-1}^{x-1} C_{sz_u+sz_v-j}^{sz_u-x}g_x \sum_{1 \leq y \leq j-x} f_{v,sz_v+1-y} \]

  • 这篇题解的写法上,上文式子中的 \(sz_u\) 并没有算入 \(sz_v\)
  • 第一个组合数:总共有 \(j-1\) 个小于 \(u\) 的排名的,选出 \(x-1\) 个给加入 \(v\) 子树前的点。
  • 第二个组合数,同理,总共有 \(sz_u+sz_v-j\) 个大于 \(u\) 的排名的。
  • 第二个求和中 \(y\) 表示枚举 \(v\) 子树中 \(v\) 的排名,\(sz_v+1-y\) 是做了一个翻转,因为我们把最后一维去掉了。
  • 注意 \(x,y\) 的枚举边界,边界不对的话复杂度就会错。和树上背包是同样的道理。

容易发现第二个求和可以前缀和优化:

\[f_{u,j}= \sum_{\max(j-sz_v,1) \leq x \leq \min(j-1,sz_u)} C_{j-1}^{x-1} C_{sz_u+sz_v-j}^{sz_u-x}g_x pre_{j-x} \]

最终的答案就是 \(\sum f_{1,i}\)

代码

完整代码见提交记录

void dfs(int u,int fa)
{
    for(int v:ve[u]) 
        if(v^fa) dfs(v,u);
    sz[u]=1;
    f[u][1]=1ll;
    for(int v:ve[u])
    {
        if(v==fa) continue;
        memcpy(g,f[u],sizeof(ll)*(sz[u]+1));
        memset(f[u],0,sizeof(ll)*(sz[u]+sz[v]+1));
        For(j,1,sz[v])
            pre[j]=(pre[j-1]+f[v][sz[v]+1-j])%mod;
        For(j,1,sz[u]+sz[v])
            For(x,max(j-sz[v],1),min(sz[u],j-1)){
                ll tmp=C(j-1,x-1)*C(sz[u]+sz[v]-j,sz[u]-x)%mod;
                qadd(f[u][j],tmp*g[x]%mod*pre[j-x]%mod);
            }
        sz[u]+=sz[v];
    }
}
posted @ 2025-03-28 21:11  wanggk  阅读(20)  评论(0)    收藏  举报