Codeforces 1332F - Independent Set(树dp)

题目链接

题意

给出一棵 n 个点树, 求它的所有非空诱导子图的独立集种类数之和, 对 998244353 取模. n ≤ 3e5.

题解

不妨假设在独立集中的点被染色成 1, 其余不染色; 由于不在诱导子图中的点不影响答案, 不妨也考虑进来, 也不染色. 问题转化为: 对这棵树的部分节点染色, 然后进行删边, 保证删边后没有相邻的点同时被染色, 并且不能有孤立的被染色的点存在, 问结果的情况种类数.

问题转化后就可以进行树 dp 了. 定义以下情况的方案数

  • \(dp[x][0]: 点 x 不染色\)
  • \(dp[x][1]: 点 x 染色\)
  • \(dp[x][2]: 点 x 染色 且其与儿子的边都删去(非法情况)\)

转态转移

  • \(dp[x][0] = \prod {dp[son][0] * 2 + dp[son][1] * 2 - dp[son][2]}\)
  • \(dp[x][1] = \prod {dp[son][0] * 2 + dp[son][1] - dp[son][2]}\)
  • \(dp[x][2] = \prod {dp[son][0] + dp[son][1] - dp[son][2]}\)

注意题目要求诱导子图是非空的, 所以最后答案要减 1, 这对应问题转化后所有边都删去的情况.

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)

const int maxn = 1e6 + 5;
const int mod = 998244353;

ll dp[maxn][3];
int n, u, v;
vector<int> g[maxn];

void dfs(int x, int par) {
    inc(i, 0, 2) dp[x][i] = 1;
    for (int son : g[x]) {
        if (son != par) {
            dfs(son, x);
            dp[x][0] =
                dp[x][0] *
                ((dp[son][0] * 2 + dp[son][1] * 2 - dp[son][2] + mod) % mod) %
                mod;
            dp[x][1] =
                dp[x][1] *
                ((dp[son][0] * 2 + dp[son][1] - dp[son][2] + mod) % mod) % mod;
            dp[x][2] = dp[x][2] *
                       ((dp[son][0] + dp[son][1] - dp[son][2] + mod) % mod) %
                       mod;
        }
    }
}

int main() {
    cin >> n;
    inc(i, 1, n - 1) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, -1);
    cout << (dp[1][0] + dp[1][1] - dp[1][2] - 1 + mod) % mod << "\n";
}

猜你喜欢

转载自www.cnblogs.com/hs-zlq/p/12635458.html