zoukankan      html  css  js  c++  java
  • CF-1332 F. Independent Set

    F. Independent Set

    题意

    一颗 n 个节点的树,求出每个(edge-induced~subgraph)的独立集个数之和。

    (edge-induced~subgraph)含义是对于边集(E,(E'subset E)),(E) 中的所有点都在该子图中。

    注意到题目要求的结果中,E' 不能为空

    分析

    首先选出子图,问题转换成在森林中选出一些点,他们互相没有边,求这样的点集的个数。对于一棵树上的问题,可以用树形DP求出

    (d[x][0]) 表示不选 x 的方案数,(d[x][1]) 表示选 x 的方案数

    (d[x][0] = prod (d[y][1] + d[y][0])\d[x][1] = prod d[y][0])

    但是此题中 x 和 y 不一定在一棵树中,所以还要考虑 (x ightarrow y) 这条边的状态。

    1. 该边在subgraph 中,则 x 的状态与 y 的状态有关联

    2. 该边不在subgraph中,则 x 的状态与 y 的状态没有关联

    考虑这两种状态,有转移方程:

    (d[x][0] = prod 2 * (d[y][1] + d[y][0]))

    (d[x][1] = prod (d[y][0] + d[y][1] + d[y][0]))

    到这里似乎问题已经得到解决,但是要注意到,“单点” 这种情况是不允许出现的,因为题目中的子图是由边集构造的,所以要考虑去除掉这种情况。

    (f[x]) 表示 x 与所有的子节点 y 所连的边都不在子图中的方案数

    在用 (f[y]) 去更新 x 时,如果 (x ightarrow y) 这条边不被选中,则 y 被选中的状态 (d[y][1]) 应该减去 (f[y]), 这代表着 y 不能作为单点被选中,所以有如下转移:

    [egin{cases} d[x][0]= prod (d[y][1]+d[y][0]) + (d[y][1]-f[y]+d[y][0]) \ d[x][1] = prod (d[y][0]) + (d[y][1] - f[y] + d[y][0])\ f[x] = prod (d[y][1]-f[y]+d[y][0]) end{cases} ]

    最终答案应该是 (d[1][0]+d[1][1]-f[1]-1), 最后减去 1 是减去了空子图的情况

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    #define dbg(x...) do { cout << "33[32;1m" << #x <<" -> "; err(x); } while (0)
    void err() { cout << "33[39;0m" << endl; }
    template<class T, class... Ts> void err(const T& arg,const Ts&... args) { cout << arg << " "; err(args...); }
    const int N = 300000 + 5;
    const int mod = 998244353;
    int head[N], ver[N<<1], nxt[N<<1], tot;
    int n;
    ll d[N][2], f[N];
    void add(int x, int y){
        ver[++tot] = y, nxt[tot] = head[x], head[x] = tot;
    }
    void dfs(int x, int fa){
        d[x][0] = d[x][1] = f[x] = 1;
        for(int i=head[x];i;i=nxt[i]){
            int y = ver[i];
            if(y == fa) continue;
            dfs(y, x);
            d[x][0] = d[x][0] * ((2 * d[y][0] + 2 * d[y][1] - f[y])%mod) % mod;
            d[x][1] = d[x][1] * ((2 * d[y][0] + d[y][1] - f[y]) % mod) % mod;
            f[x] = f[x] * ((d[y][0] + d[y][1] - f[y]) % mod) % mod;
        }
         dbg(x, d[x][0], d[x][1], f[x]);
    }
    int main(){
        scanf("%d", &n);
        for(int i=2;i<=n;i++){
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dfs(1, 0);
        cout << (d[1][0] + d[1][1] - f[1] - 1 + 2 * mod) % mod;
        return 0;
    }
    

    这题代码很容易写,关键是要把DP转移搞清楚,CF的题目解释很清晰,而且样例还给解释,要是放在比赛上能遇到这样的Hint就谢天谢地了

  • 相关阅读:
    pycharm连接远程服务器(拉取版本)
    Xftp5中文文件乱码
    pycharm连接远程服务器
    Centos中使用virtualenvwrapper
    VNC连接centos图形化界面
    PIP设置镜像源
    Java实现地理坐标判断
    词袋模型和句子相似度
    词向量入门
    《深入理解 Java 虚拟机》读书笔记:类文件结构
  • 原文地址:https://www.cnblogs.com/1625--H/p/12655281.html
Copyright © 2011-2022 走看看