zoukankan      html  css  js  c++  java
  • AT5762 Preserve Diameter

    Link
    首先我们可以发现(H)的直径是唯一的,否则不论如何加边都不会使得其直径长度减小。

    (H=(V,E))的直径为((s,t)),长度为(l),建出(H)的任意一棵(s)为根的bfs树(我们认为(dep_s=0)),那么这棵(H)满足:
    (1.forall|dep_u-dep_v|>1,(u,v) otin E)
    (1.forall|dep_u-dep_v|le1,(u,v)in E)
    (3.{x|dep_x=l}={t})

    注意到(G=(V',E'))中,所有直径的中点都是同一个(点或边)。不妨认为(2|l),这样直径中点就是点(x)

    对于合法的(H),建出以(x)为根的bfs树,并求出其(dep)数组(依旧认为(dep_0=0)),观察发现一个合法的(H)会对应两个合法的(dep)数组。
    因此我们要对合法的(dep)数组计数,合法的(dep)数组应该满足下列条件:
    (1.forall kin[-frac l2,frac l2],exists x,s.t. dep_x=k)
    (2.operatorname{ord}({x|dep_x=frac l2})=operatorname{ord}({x|dep_x=-frac l2})=1)
    (3.forall(u,v)in E',|dep_u-dep_v|le1)

    考虑树形dp,设(f_{u,0/1/2,0/1/2})为只考虑(u)子树,存在(0/1/ge2)个点(v)满足(dep_v-dep_u=mx_u),存在(0/1/ge2)个点(v)满足(dep_u-dep_v=mx_u)的方案数。其中(mx_u)(u)子树中的最大深度。
    对于((u,v))这条边,枚举(dep_u-dep_v=-1/0/1)然后直接转移即可。

    还有一种情况是(2 mid l)即中点为一条边((u,v)),将这条边断掉之后分别对(u,v)两棵子树进行树形dp,然后手动合并即可。

    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    const int N=300007,P=998244353,i2=P-P/2;
    int m,root,len,fa[N],dia[N],f[N][3][3],g[3][3];std::vector<int>e[N];
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    int mul(int a,int b){return 1ll*a*b%P;}
    int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
    void dfs(int u,int dep)
    {
        if(dep>len) len=dep,root=u;
        for(int v:e[u]) if(v^fa[u]) fa[v]=u,dfs(v,dep+1);
    }
    void dp(int u,int fa,int d)
    {
        (d==m/2? f[u][1][1]:f[u][0][0])=1;
        for(int v:e[u])
        {
    	if(v==fa) continue;
    	dp(v,u,d+1),memset(g,0,36);
    	for(int x=0;x<3;++x) for(int y=0;y<3;++y) for(int p=0;p<3;++p) for(int q=0;q<3;++q) for(int k=0,r,t;k<3;++k) r=std::min(2,x+p*(k==1)),t=std::min(2,y+q*(k==2)),inc(g[r][t],mul(f[u][x][y],f[v][p][q]));
    	memcpy(f[u],g,36);
        }
    }
    int main()
    {
        int n=read(),p,q;
        for(int i=1,u,v;i<n;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
        dfs(1,1),memset(fa+1,0,n<<2),len=0,dfs(root,1);
        for(int i=root;i;i=fa[i]) dia[++m]=i;
        if(m&1) p=dia[m/2+1],dp(p,0,0),printf("%d",mul(i2,f[p][1][1]));
        else p=dia[m/2],q=dia[m/2+1],dp(p,q,1),dp(q,p,1),printf("%d",mul((1ll*f[p][1][0]+f[p][1][1]+f[p][1][2])%P,(1ll*f[q][1][0]+f[q][1][1]+f[q][1][2])%P));
    }
    
  • 相关阅读:
    Sphinx 自动化文档
    手把手教你用Rancher创建产品质量数据库设置
    手把手教你用Rancher创建产品质量数据库设置
    手把手教你用Rancher创建产品质量数据库设置
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    九、新人成才之路《成才大原则 谈人生大规划》
    Linux常用命令大全(非常全!!!)
    Linux常用命令大全(非常全!!!)
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12678379.html
Copyright © 2011-2022 走看看