zoukankan      html  css  js  c++  java
  • Codeforces1146F. Leaf Partition

    Description

    You are given a rooted tree with n nodes, labeled from (1) to (n). The tree is rooted at node (1). The parent of the i-th node is (p_i). A leaf is node with no children. For a given set of leaves (L), let (f(L)) denote the smallest connected subgraph that contains all leaves (L).
    You would like to partition the leaves such that for any two different sets (x,y) of the partition, (f(x)) and (f(y)) are disjoint.
    Count the number of ways to partition the leaves, modulo 998244353. Two ways are different if there are two leaves such that they are in the same set in one way but in different sets in the other.

    Input

    The first line contains an integer (n) ((2≤n≤200000)) — the number of nodes in the tree.
    The next line contains n−1 integers (p_2, p_3, ldots, p_n) ((1 leq p_i < i)).

    Output

    Print a single integer, the number of ways to partition the leaves, modulo 998244353.

    Solution

    题目大意就是将一棵树的叶子节点分成多个连通块,连通块中包含着叶子节点及叶子节点之间的路径,使连通块的交集为空集,求方案数
    一道树形DP
    设f[i][0/1]表示第i个点是否向上延申与其他子树的节点(非父亲节点)联通
    对于每一个点i,不管非法方案,总方案数都是(prod f[x][0]+f[x][1](x∈son[i]))
    现在考虑一下非法方案
    1、对于不向上延伸:
    如果只有一个子节点延申,那么显然是不合法的,因为该子节点无法与其他节点联通
    对于一个点i,这种情况的方案数是(sum frac{prod f[x][0]}{f[x'][0]} imes f[x'][1](x,x'∈son[i]))
    2、对于向上延申:
    如果没有子节点向上延申,显然也是不合法的,因为该点就无法向上了
    该方案数为(prod f[x][0](x∈son[i]))

    Code

    #include <cstdio>
    #include <algorithm>
    #define MO 998244353
    #define N 200001 
    #define LL long long
    #define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
    using namespace std;
    int n,i,len,x,go[N],to[N],last[N];
    LL f[N][2];
    void make(int x,int y)
    {
        go[++len]=y;to[len]=last[x];last[x]=len;
    }
    LL ksm(LL x,int y)
    {
        LL sum=1;
        while (y)
        {
            if (y&1) sum=sum*x%MO;
            x=x*x%MO;
            y>>=1;
        }
        return sum;
    }
    void dfs(int x)
    {
        if (!last[x])
        {
            f[x][0]=f[x][1]=1;
            return;
        }
        LL s=1,tot=1,s1=0;
        for (int k=last[x];k;k=to[k])
        {
            dfs(go[k]);
            s=s*(f[go[k]][0]+f[go[k]][1])%MO;
            tot=tot*f[go[k]][0]%MO;
        }
        f[x][1]=(s-tot+MO)%MO;
        for (int k=last[x];k;k=to[k])
        {
            s1=(s1+tot*ksm(f[go[k]][0],MO-2)%MO*f[go[k]][1]%MO)%MO;
        }
        f[x][0]=(s-s1+MO)%MO;
    }
    int main()
    {
        open("1146F");
        scanf("%d",&n);
        for (i=2;i<=n;i++)
        {
            scanf("%d",&x);
            make(x,i);
        }
        dfs(1);
        printf("%lld",f[1][0]);
        return 0;
    }
    
    
    如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.
  • 相关阅读:
    NFC读写电子便签总结
    对字符串md5加密
    把ArrayList集合中的字符串内容写到文本文件中
    【原创】关于jquery实现格式化时间
    jQuery插件之ajaxFileUpload
    jxl读取excel实现导入excel写入数据库
    jxl写入excel实现数据导出功能
    多个Jar包的合并操作
    基于git的源代码管理模型——git flow
    Google Gson 使用简介
  • 原文地址:https://www.cnblogs.com/Sport-river/p/13866056.html
Copyright © 2011-2022 走看看