首页 > 其他分享 >P9669 [ICPC2022 Jinan R] DFS Order 2

P9669 [ICPC2022 Jinan R] DFS Order 2

时间:2023-10-24 20:35:04浏览次数:32  
标签:ICPC2022 int Jinan dfs Order ans son 节点 times

Description

P 有一棵树,根节点是 \(1\),总共有 \(n\) 个节点,从 \(1\) 到 \(n\) 编号。

他想从根节点开始进行深度优先搜索。他想知道对于每个节点 \(v\),在深度优先搜索中,它出现在第 \(j\) 个位置的方式有多少种。深度优先搜索的顺序是在搜索过程中访问节点的顺序。节点出现在第 \(j(1 \leq j \leq n)\) 个位置表示它在访问了 \(j-1\) 个其他节点之后才被访问。因为节点的子节点可以以任意顺序访问,所以有多种可能的深度优先搜索顺序。

P 想知道对于每个节点 \(v\),有多少种不同的深度优先搜索顺序,使得 \(v\) 出现在第 \(j\) 个位置。对于每个 \(v\) 和 \(j(i \leq v, j \leq n)\),计算答案。答案可能很大,所以输出时要取模 \(998244353\)。以下是深度优先搜索的伪代码,用于处理树。在调用 main() 函数后,dfs_order 将会包含深度优先搜索的顺序。

https://z1.ax1x.com/2023/10/24/piEhAWq.png

Solution

先考虑怎么求总方案数。设 \(t_x\) 表示以 \(x\) 为根节点的子树的总方案数。有 \(t_x=son_x!\times \Pi_{y\in son} t_{y}\)(\(son_x\) 表示 \(x\) 的儿子数)。

设 \(ans_{x,i}\) 表示点 \(i\) 在 \(\text{dfs}\) 序中的位置为 \(i\) 的答案(不考虑 \(x\) 子树内部的顺序)。因为 \(\text{dfs}\) 是从 \(x\) 走到 \(x\) 的儿子 \(y\),所以转移也考虑从 \(x\) 转移到 \(y\)。枚举 \(y\) 和 \(x\) 的 \(\text{dfs}\) 序差几,有 \(ans_{y,j}=\sum ans_{x,i}\times g_{j-i}\),其中 \(g_{j-i}\) 表示在 \(\text{dfs}\) 序中 \(y\) 与 \(x\) 差 \(j-i\) 的方案数。

考虑 \(g\) 的转移。枚举当前节点 \(y\) 前有多少个点 \(i\),它们的大小的和是 \(j\)。设 \(f_{i,j}\) 表示在 \(x\) 的儿子中选了 \(i\) 个,大小为 \(j\) 的方案数。\(f\) 可以用背包来维护。那么 \(g_{j+1}=\sum f_{i,j}\times j!\times (son_x-1-j)!\times \frac{t_x}{t_y\times son_x!}\)。其中,\(j!\) 和 \((son_x-1-j)!\) 分别表示 \(y\) 前和 \(y\) 后的兄弟节点的排列顺序,\(\frac{t_x}{t_y\times son_x!}\) 表示 \(x\) 的儿子中,除了 \(y\) 的子树内部方案数的积。因为 \(ans\) 定义的时候就要求不能考虑 \(y\) 子树内部的方案数,因此要除去 \(y\) 的子树带来的贡献。

那么最后答案为 \(ans_{x,i}\times t_x\)。

但是,求 \(f\) 的过程是 \(\mathcal O(n^4)\) 的。因此考虑写回滚背包,就是先求出所有儿子带来的贡献,再减去目标儿子节点带来的贡献即可。优化至 \(\mathcal O(n^3)\)。

Code

#include<cstdio>
#include<cstring>
#define N 505
#define mod 998244353
#define ll long long
using namespace std;
int n,tot,son[N],siz[N];
ll jc[N],ans[N][N],f[N][N],g[N],t[N];
struct node {int to,next,head;}a[N<<1];
void add(int x,int y)
{
    a[++tot].to=y;a[tot].next=a[x].head;a[x].head=tot;
    a[++tot].to=x;a[tot].next=a[y].head;a[y].head=tot;
}
ll ksm(ll x,ll y)
{
    ll res=1;
    while (y)
    {
        if (y&1) res=res*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return res;
}
void gett(int x,int fa)
{
    ll res=1;
    siz[x]=1;t[x]=1;
    for (int i=a[x].head;i;i=a[i].next)
    {
        int y=a[i].to;
        if (y==fa) continue;
        gett(y,x);
        son[x]++;siz[x]+=siz[y];
        t[x]=t[x]*t[y]%mod;
    }
    t[x]=t[x]*jc[son[x]]%mod;
}
void dfs(int x,int fa)
{
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for (int i=a[x].head;i;i=a[i].next)
    {
        int y=a[i].to;
        if (y==fa) continue;
        for (int j=son[x];j;--j)
            for (int k=siz[y];k<=siz[x];++k)
                f[j][k]=(f[j][k]+f[j-1][k-siz[y]])%mod;
    }
    for (int i=a[x].head;i;i=a[i].next)
    {
        int y=a[i].to;
        ll base=t[x]*ksm(t[y],mod-2)%mod*ksm(jc[son[x]],mod-2)%mod;
        if (y==fa) continue;
        for (int j=1;j<=son[x];++j)
            for (int k=siz[y];k<=siz[x];++k)
                f[j][k]=(f[j][k]-f[j-1][k-siz[y]]+mod)%mod;
        memset(g,0,sizeof(g));
        for (int j=0;j<son[x];++j)
            for (int k=0;k<siz[x];++k)
                g[k+1]=(g[k+1]+f[j][k]*jc[j]%mod*jc[son[x]-1-j]%mod*base%mod)%mod;
        for (int j=1;j<=n;++j)
            for (int k=j+1;k<=n;++k)
                ans[y][k]=(ans[y][k]+ans[x][j]*g[k-j]%mod)%mod;
        for (int j=son[x];j;--j)
            for (int k=siz[y];k<=siz[x];++k)
                f[j][k]=(f[j][k]+f[j-1][k-siz[y]])%mod;
    }
    for (int i=a[x].head;i;i=a[i].next)
    {
        int y=a[i].to;
        if (y==fa) continue;
        dfs(y,x);
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;++i)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    jc[0]=1;
    for (int i=1;i<=n;++i)
        jc[i]=jc[i-1]*(ll)i%mod;
    gett(1,0);
    ans[1][1]=1;
    dfs(1,0);
    for (int i=1;i<=n;++i)
    {
        for (int j=1;j<=n;++j)
            printf("%lld ",ans[i][j]*t[i]%mod);
        printf("\n");
    }
    return 0;
}

标签:ICPC2022,int,Jinan,dfs,Order,ans,son,节点,times
From: https://www.cnblogs.com/Livingston/p/17785680.html

相关文章

  • 求工资表中工资比较高的10个人 是排序问题 先 order by sal desc 再limit 10
     自己写的错误的 ......
  • 排序 order by 默认升序;降序 desc;两个条件一起使用时使用逗号隔开
     #先用工资排序,如果工资相等,再用名字排序select*fromemporderbysaldesc,ENAMEdesc;  ......
  • r - How do I order by row.names in dataframe R语言 排序
     new_df<-df[order(row.names(df)),]REF:https://stackoverflow.com/questions/20295787/how-can-i-use-the-row-names-attribute-to-order-the-rows-of-my-dataframe-in-rhttps://stackoverflow.com/questions/25194196/how-do-i-order-by-row-names-in-dataframe......
  • Binary Tree Postorder Traversal
    SourceGivenabinarytree,returnthepostordertraversalofitsnodes'values.ExampleGivenbinarytree{1,#,2,3},1\2/3return[3,2,1].ChallengeCanyoudoitwithoutrecursion?题解1-递归首先使用递归便于理解。C++-Tra......
  • Databend join reorder 策略
    joinorder的重要性Joinorder是指在执行SQL查询时,决定多个表进行join的顺序。它是数据库查询优化的一个重要方面,对查询性能和效率有着重要的影响,不同的joinorder对性能可能有数量级的影响。优化器优化joinorder的核心流程joinplan枚举根据统计信息估算结果的......
  • SQLAlchemy学习-12.查询之 order_by 按desc 降序排序
    前言sqlalchemy的query默认是按id升序进行排序的,当我们需要按某个字段降序排序,就需要用到order_by。order_by排序默认情况下sqlalchemy的query默认是按id升序进行排序的res=session.query(Project).all()print(res)#[<Project(id='1',project_name='string'.........
  • 无涯教程-Derby - Order By语句
    ORDERBY子句用于按其使用关键字的顺序排列输出集的内容,ASC代表升序,DESC代表降序,如果您不提及其中任何一个,则默认情况下内容将按升序排列。OrderBy-语法以下是ORDERBY子句的语法-SELECT*FROMtable_nameORDERBYcolumn_nameASC|DESC.OrderBy-命令行示例假设无涯......
  • 关联容器(map、set、multimap、multiset、pair、unordered_map)
    一、使用关联容器key---value)对:关键字起到索引的作用,值则表示与索引相关联的数据。set中每个元素只包含一个关键字;set支持高效的关键字查询操作---检查一个关键字是否在set中。multimap允许多个元素具有相同的关键字。   pair类型用于保存两个数据类型,pair的数据成员是public......
  • (unordered_)set,(unordered_)map,数组(vector)
    set:保证元素的唯一性,并且元素从小到大排序unordered_set:保证元素的唯一性,并且元素的顺序未知,不一定和输入相同map:键从小到大排序unordered_map:键的顺序未知,不一定和输入相同数组(vector):元素的顺序和输入相同......
  • CF1010C Border 题解
    题目传送门前置知识最大公约数|裴蜀定理简化题意给定一个长度为\(n\)的序列\(a\),求能用\(r=(\sum\limits_{i=1}^{n}d_ia_i)\bmodk\)表示的不同的\(r\)的个数及所有情况,其中对于每一个\(i(1\lei\len)\)均有\(d_i\)为非负整数。解法依据裴蜀定理,不难得到存......